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 { sum+=arr[x]; System.out.println("sum="+sum); } 操作数组,通常都会用到for循环~ 一个例子: //定义功能:用于打印数组中的元素,元素间用逗号隔开。 System.out.print("["); for(int x=0;x { if(x!=arr.length-1) System.out.print(arr[x]+","); else System.out.print(arr[x]+"]"); } 运行下述语句会出现下述结果,说明把数组的地址给输出啦。 System.out.println(arr); 获取数组中的最大值: 思路: 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 { 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 { if(arr[x]>max) max=x; } return arr[max]; } 获取最小值也是同理。 选择排序思想: 以从小到大排序为例: 先用0角标位置的元素依次和后面的元素相比,如果后面位置的元素比角标位置元素小,则将该位置元素与0角标位置元素做交换。比完所有元素之后,0角标位置存放的将是数组中的最小元素。接着,将1角标元素依次和后面的元素相比,......,1角标位置存放的将是数组中次小元素。依次类推,就可以排序完成。 public static void selectSort(int[] arr) { for(int x=0;x { for(int y=x+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,没有必要遍历到最后一个角标,因为最后只剩一个元素了,没有和它比的了~ 选择排序特点: 内循环结束一次,最值出现在头角标位置上。 冒泡排序思想: 相邻的两个元素进行比较,如果符合条件就换位。 每循环一次,最值出现在最后位,最末一个元素下次就不参与循环了。 小的元素往前跑,大的元素往后跑,这就是冒泡排序的思想。 public static void bubbleSort(int[] arr) { for(int x=0;x { for(int y=0;y { 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,应付面试。去面试,面试官说,来~写个冒泡排序~ 不管是什么排序方法,都有一个共性:都需要对满足条件的元素进行位置置换,所以我们可以把换位置这个功能提取出来,封装成一个函数。 public static void swap(int[]arr,int a,int b) { int temp=arr[a]; arr[a]=arr[b]; arr[b]=temp; } //定义功能:获取key第一次出现在数组中的位置。如果返回是-1,那么代表该key在数组中不存在。 public static int getIndex(int[] arr,int key) { for(int x=0;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 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 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这个位置。 十进制---->二进制: 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反转,这样就正啦 } 十进制---->十六进制: 思想: 接下来用代码来体现: 那么右移的循环次数应该是多少呢?因为是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()); } 什么叫查表法呢? 即将这种一一对应关系先存到一个表里面去,后面再来查询这个表~ 查表法:将所有的元素临时存储起来,建立对应关系。 每一次&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 { System.out.print(arr[x]+","); } } //定义二进制的表 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 { System.out.print(arr[x]); } 我们发现两种进制转换之间有很多共性的过程,我们把这个过程抽取出来,封装到一个函数中~ 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 { 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); } 二维数组,可以理解为,数组中的数组。 初始化方式: 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 { for(int y=0;y { sum=sum+arr[x][y]; } System.out.println("sum="+sum); } 这次课程的容量感觉比以前要小~概念少,代码多~ 所以完成的速度要比以前快一些~但依然成就感满满。继续加油,小楠楠( ˘ ³˘)♥
03-数组(常见操作-获取最值)
04-数组(排序-选择排序)
05-数组(排序-冒泡排序)
06-数组(排序-位置置换功能抽取)
07-数组(折半查找)
08-数组(十进制-二进制)
09-数组(十进制-十六进制)
10-数组(查表法十进制-十六进制)
11-数组(查表法十进制-二进制)
12-数组(进制转换优化)
13-数组(二维数组)
14-数组(二维数组练习)