01-数组(静态初始化-常见问题)
数组的定义方式:
int[] arr=new int[2];
或者
int arr[]=new int[2];
虽然两种都可以,但还是用第一种方式比较规范哦。
还有一种定义方式:
int[] arr=new int[]{3,1,6,5,4};
这种方式叫做静态初始化方式。创建了一个数组实体,并且给这个实体中的每一个位置都添加了元素。
注意后面的方括号里不要写长度,因为写了长度容易出错~而且数字的个数和数值都已经列举出来了,再写长度也没有必要~
它的简化形式为:
int[] arr={3,1,6,5,4};
一般在数据明确的情况下都可以用这种简化形式,数据不明确的话还是乖乖用第一种~
例:
int[] arr=new int[5];
arr[0]=90;
arr[1]=80;
数组的一些常见问题:
没有结果。
但是编译的时候为什么没有错误提示呢?
因为编译只检查语法错误,而到运行的时候,才会到堆内存当中去开辟一个数组空间,并分配0、1、2这三个角标,这时,当你想要打印3号角标的时候发现不存在,才会产生问题。
所以运行的时候就会产生问题啦:
这个问题是:数组角标越界异常,具体哪个角标越界了,会显示在上面框出的那句话后面。
红框框出来的那句话意思是:操作数组时,访问到了数组中不存在的角标。
还有一种情况,也是编译时没有问题,运行时会报错:
红框里的话报错内容为:空指针异常:当引用没有任何指向,值为null的情况时,该引用还用于操作实体。
02-数组(常见操作-遍历)
数组的操作:
获取数组中的元素。通常会用到遍历。
例:
int[] arr=new int[3];
for(int x=0;x<3;x++)
{
System.out.println("arr["+x+"]="+arr[x]+";");
}
用for循环,循环结束变量就消失啦,不再占用内存。
数组中有一个属性可以直接获取到数组元素的个数。
使用方式:数组名称.length=
例:
int[] arr={3,6,5,1,8,9,67};
System.out.println("length:"+arr.length);
for(int x=0;x<arr.length;x++)
{
System.out.println("arr["+x+"]="+arr[x]+";");
}
求和:
int sum=0;
for(int x=0;x<arr.length;x++)
{
sum+=arr[x];
System.out.println("sum="+sum);
}
操作数组,通常都会用到for循环~
一个例子:
//定义功能:用于打印数组中的元素,元素间用逗号隔开。
System.out.print("[");
for(int x=0;x<arr.length;x++)
{
if(x!=arr.length-1)
System.out.print(arr[x]+",");
else
System.out.print(arr[x]+"]");
}
运行下述语句会出现下述结果,说明把数组的地址给输出啦。
System.out.println(arr);
03-数组(常见操作-获取最值)
获取数组中的最大值:
思路:
1,获取最值需要进行比较,每一次比较都会有一个较大的值,因为该值不确定。通过一个变量进行存储。
2,让数组中的每一个元素都和这个变量中的值进行比较。
如果大于变量中的值,就用该变量记录较大值。
3,当所有的元素都比较完成,那么该变量中存储的就是数组中的最大值。
步骤:
1,定义变量。初始化为数组中任意一个元素即可。
2,通过循环语句对数组进行遍历。
3,在变量过程中定义判断条件,如果遍历到的元素比变量中的元素大,就赋值给该变量。
需要定义一个功能来完成,以便提高复用性。
1,明确结果,数组中的最大元素 int
2,未知内容:一个数组,int[]
public static int getMax(int[] arr)
{
int max=arr[0];
for(int x=1;x<arr.length;x++)
{
if(arr[x]>max)
max=arr[x];
}
return max;
}
获取最大值的另一种方式,可不可以将临时变量初始化为0呢?
但是如果这个数组中全是负数,临时变量初始化为0就不可行。
换一个思路,我们不仅可以将临时变量初始化为数组中的元素,也可以初始化为数组的角标。这样就可以将临时变量初始化为0啦。
public static int getMax(int[] arr)
{
int max=0;
for(int x=1;x<arr.length;x++)
{
if(arr[x]>max)
max=x;
}
return arr[max];
}
获取最小值也是同理。
04-数组(排序-选择排序)
选择排序思想:
以从小到大排序为例:
先用0角标位置的元素依次和后面的元素相比,如果后面位置的元素比角标位置元素小,则将该位置元素与0角标位置元素做交换。比完所有元素之后,0角标位置存放的将是数组中的最小元素。接着,将1角标元素依次和后面的元素相比,......,1角标位置存放的将是数组中次小元素。依次类推,就可以排序完成。
public static void selectSort(int[] arr)
{
for(int x=0;x<arr.length-1;x++)
{
for(int y=x+1;y<arr.length-1;y++)
{
if(arr[x]>arr[y])
{
int temp=arr[x];
arr[x]=arr[y];
arr[y]=arr[temp];
}
}
}
}
两个问题:
1,返回值类型,假设传进来的数组为a,那么操作原数组arr和操作a,其实都是在操作同一个数组实体,只是多个引用在操作同一个数组。因此不用返回a,因为arr和a都指向同一个数组。所以返回值类型为void。
2,没有必要遍历到最后一个角标,因为最后只剩一个元素了,没有和它比的了~
选择排序特点:
内循环结束一次,最值出现在头角标位置上。
05-数组(排序-冒泡排序)
冒泡排序思想:
相邻的两个元素进行比较,如果符合条件就换位。
每循环一次,最值出现在最后位,最末一个元素下次就不参与循环了。
小的元素往前跑,大的元素往后跑,这就是冒泡排序的思想。
public static void bubbleSort(int[] arr)
{
for(int x=0;x<arr.length-1;x++)
{
for(int y=0;y<arr.length-x-1;y++)//-x:让每一个比较的元素减少,-1:避免角标越界
{
if(arr[y]>arr[y+1])
{
int temp=arr[y];
int arr[y]=arr[y+1];
int arr[y+1]=temp;
}
}
}
}
选择和冒泡排序是面试中最经常被问到的,排序的代码写法有很多,这只是其中一种。如果需要排序的元素不多,可以采用上面这种写法,如果比较多,用这种写法效率就不高啦。
优化的方法的思想:在比较的过程中,为了减少在堆内存中换位置的次数,则先不换位置,在栈内存中记录下每次比较的结果,当一个内循环结束后,确定了最末位置是最值后,直接将最后一次比较的元素进行交换即可。一次内循环下来,堆内存中就只换了一次位置。
而在真实的Java开发中,我们不用选择也不用冒泡,我们用到的排序方法是Arrays.sort(arr);,这是Java怕我们不会排序,特意提供给我们的排序方法,哈哈~(import java.util.*;)
这就意味着我们不用学选择排序和冒泡排序吗?
不。
我们依然要学,原因有两个:
1,我们可以借此了解排序中的算法。
2,应付面试。去面试,面试官说,来~写个冒泡排序~
06-数组(排序-位置置换功能抽取)
不管是什么排序方法,都有一个共性:都需要对满足条件的元素进行位置置换,所以我们可以把换位置这个功能提取出来,封装成一个函数。
public static void swap(int[]arr,int a,int b)
{
int temp=arr[a];
arr[a]=arr[b];
arr[b]=temp;
}
07-数组(折半查找)
//定义功能:获取key第一次出现在数组中的位置。如果返回是-1,那么代表该key在数组中不存在。
public static int getIndex(int[] arr,int key)
{
for(int x=0;x<arr.length;x++)
{
if(arr[x]==key)
{
return x;//返回该元素的角标
}
return -1;//代表没有找到
}
}
接下来介绍另外一种更有效率的查找方式:折半查找。
缩小范围的查找会使查找速度更快,但是这种查找方式要求数组必须是有序的。
public static int halfSearch(int[] arr,int key)
{
int min,max,mid;
min=0;
max=arr.length-1;
mid=(max+min)/2;
if(arr[mid]!=key)
{
if(key>arr[mid])
min=mid+1;
else if(key<arr[mid])
max=mid-1;
if(min>max)
return -1;
mid=(max+min)/2;
}
return mid;
}
折半的第二种方式:
public static int halfSerch_2(int[] arr,int key)
{
int min=0,max=arr.length-1,mid;
while(min<=max)
{
mid=(max+min)>>1;//也是除以2的意思
if(key>arr[mid])
min=mid+1;
else if(key<arr[mid])
max=mid-1;
else
return mid;
}
return -1;
}
练习:有一个有序的数组,想要将一个元素插入到该数组中,还要保证该数组是有序的。如何获取该元素在数组中的位置。
min就是8最后要插入的位置。
public static int getIndex_2(int[] arr,int key)
{
int min=0,max=arr.length-1,mid;
while(min<=max)
{
mid=(max+min)>>1;//也是除以2的意思
if(key>arr[mid])
min=mid+1;
else if(key
max=mid-1;
else
return mid;
}
return min;//其实和上面代码不同的部分就只是将return -1改成return min。
}
这段代码的思想是,在数组中寻找8的位置,如果存在,则将8插入在这个位置;如果不存在,则将8插入min这个位置。
08-数组(十进制-二进制)
十进制---->二进制:
public static void toBin(int num)
{
StringBuffer sb=new StringBuffer();//先不要管这是什么数据类型,直到它可以存入数据就对啦
while(num>0)
{
//System.out.println(num%2);这样打出来是反的
sb.append(num%2);//将数据存入sb
num=num/2;
}
System.out.println(sb.reverse());//reverse为将sb反转,这样就正啦
}
09-数组(十进制-十六进制)
十进制---->十六进制:
思想:
接下来用代码来体现:
那么右移的循环次数应该是多少呢?因为是32位,所以最多右移8次~
public static void toHex(int num)
{
for(int x=0;x<8;x++)
{
int temp=num&15;
if(temp>9)
System.out.println((char)(temp-10+'A'));
else
System.out.println(temp);
num=num>>>4;
}
}
但这样输出是反哒,换个方法:
public static void toHex(int num)
{
StringBuffer sb=new StringBuffer();
for(int x=0;x<8;x++)
{
int temp=num&15;
if(temp>9)
sb.append((char)(temp-10+'A'));
else
sb.append(temp);
num=num>>>4;
}
System.out.println(sb.reverse());
}
10-数组(查表法十进制-十六进制)
什么叫查表法呢?
即将这种一一对应关系先存到一个表里面去,后面再来查询这个表~
查表法:将所有的元素临时存储起来,建立对应关系。
每一次&15后的值作为索引去查建立好的表,就可以找到对应的元素。
这样比-10+‘a’更方便好用。
这个表怎么建立呢?
可以通过数组的形式来定义。
public static void toHex(int num)
{
char[] chs={'0','1','2','3'
,'4','5','6','7'
,'8','9','A','B'
,'C','D','E','F'};
//定义一个临时容器
char[] arr=new char[8];//字符数组的默认初始化值是'\u0000',相当于一个空格
int pos=arr.length;
while(num!=0)//一旦num为0,说明有效位已经都右移完啦,前面的就都是0不用再取啦
{
int temp=num&15;
//System.out.println(chs[temp]);
arr[--pos]=chs[temp];
num=num>>>4;
}
//存储数据的arr数组遍历
for(int x=pos;x<arr.length;x--)//数据是从数组最后一位开始存的,打印的时候正着打就完全OK~
{
System.out.print(arr[x]+",");
}
}
11-数组(查表法十进制-二进制)
//定义二进制的表
char[] chs={'0','1'};
//定义一个临时存储容器
char[] arr=new char[32];//32个足够装啦
//定义一个操作数组的指针
int pos=arr.length;
while(num!=0)
{
int temp=num&1;
arr[--pos]=chs[temp];
num=num>>>1;
}
for(int x=pos;x<arr.length;x++)
{
System.out.print(arr[x]);
}
12-数组(进制转换优化)
我们发现两种进制转换之间有很多共性的过程,我们把这个过程抽取出来,封装到一个函数中~
public static void trans(int num,int base,int offset)
{
if(num==0)
{
System.out.println(0);
return;
}
char[] chs={'0','1','2','3'
,'4','5','6','7'
,'8','9','A','B'
,'C','D','E','F'};
char[] arr=new char[32];
int pos=arr.length;
while(num!=0)
{
int temp=num&base;
arr[--pos]=chs[temp];
num=num>>>offset;
}
for(int x=pos;x<arr.length;x++)
{
System.out.print(arr[x]);
}
}
然后要定义功能函数来调用它~
/*
十进制---->二进制
*/
public static void toBin(int num)
{
trans(num,1,1);
}
/*
十进制---->八进制
*/
public static void toBa(int num)
{
trans(num,7,3);
}
/*
十进制---->十六进制
*/
public static void toHex(int num)
{
trans(num,15,4);
}
13-数组(二维数组)
二维数组,可以理解为,数组中的数组。
初始化方式:
int[][] arr=new int[3][4];//定义了名称为arr的二维数组, 二维数组中有3个一维数组,每个一维数组中有四个元素。
另一种初始化方式:
int[][] arr=new int[3][];
System.out.println(arr[0]);//结果为null
对它进行初始化:
int[][] arr=new int[3][];
arr[0]=new int[3];
arr[1]=new int[1];
arr[2]=new int[2];//对数组中的每一个小数组进行了手动初始化
System.out.println(arr[0]);//结果为null
这时在内存中的表示为:
System.out.println(arr.length);//打印的是二维数组的长度 3;
System.out.println(arr[0].length);//打印二维数组中第一个一维数组长度
再一种初始化方式~:
int[][] arr={{3,5,1,7},{2,3,5,8},{6,1,8,2}};
int sum=0;
for(int x=0;x<arr.length;x++)
{
for(int y=0;y<arr[x].length;y++)
{
sum=sum+arr[x][y];
}
System.out.println("sum="+sum);
}
14-数组(二维数组练习)
这次课程的容量感觉比以前要小~概念少,代码多~
所以完成的速度要比以前快一些~但依然成就感满满。继续加油,小楠楠( ˘ ³˘)♥