数组、排序和查找
1. 数组
数组可以存放多个同一类型的数据。数组也是一种数据类型,是引用类型,数组型数据是对象。
1.1 数组的定义
-
初始化:
第一种动态分配方式:数据类型[] 数组名 = new 数据类型[大小] or 数据类型 数组名[] = new 数据类型[大小],如:
int[] a = new int[3]; //或者 int a[] = new int[3]
第二种动态分配方式:也可以先定义,再初始化,如:
int[] a; a = new int[3];// 先声明一个数组 a ,再给它分配内存空间,可以存储3个 int 类型的数据,此时没有指定值,每一个值默认为 0。
第三种静态初始化:这种方式在数组的大小不大,且知道每一个具体的值时使用。
int[] a = {2, 3, 4, 5}; //还可以写为:int[] a = new[]{2,3,4,5}
-
数组被创建后,如果没有赋值,则有默认赋值:int、short、byte 和 long 默认赋值为 0,float、double 默认赋值为 0.0,char 默认赋值为 \u0000,boolean 默认赋值为 false,String 默认赋值为 null。
-
数组的下标从 0 开始的,下表必须在指定范围内使用,否则报:下标越界异常,比如:int[] arr = new int[5];有效下标为 0-4。要访问数组 a 的第 2 个元素,a[1]。
1.2 数组的赋值机制
-
数组在默认情况下是引用传递,赋的值是地址,赋值方式为引用赋值。如:
int[] arr1 = {1, 2, 3}; int[] arr2 = arr1; //不是值的拷贝,而是共享同一个地址 arr2[0] = 10; //此时 arr1[0] 也会变成 10
-
拷贝一个数组给另一个数组(不是上面的地址传递),操作如下:
int[] arr1 = {10, 20, 30}; int[] arr2 = new int[arr1.length]; for(int i=0; i<arr1.length; i++){ arr2[i] = arr1[i]; //这样他们的数据空间就不会影响,此时修改 arr2 不会影响 arr1 }
1.3 数组翻转
-
方式1:传统翻转,通过中间变量,如:
int[] arr = {11, 22, 33, 44, 55, 66}; int temp = 0; int len = arr.length; for(int i=0; i < len/2; i++){ temp = arr[len -1 -i]; arr[len -1 -i] = arr[i]; arr[i] = temp; }
-
方式2:逆序赋值方式,如:
int[] arr1 = {11, 22, 33, 44, 55, 66}; int[] arr2 = new int[arr1.length]; for(int i = arr1.length -1, j=0 ; i>=0 ; i--, j++){ arr2[j] = arr1[i]; } //上面的步骤结束后,arr2 的值就是 arr1 值的翻转了,但是他们并不指向同一个地址,所以有如下操作 arr1 = arr2; //arr1 指向 arr2 的地址,此时 arr1 原来的数据空间没有变量使用了,就会被当做垃圾,销毁。 //此时输出 arr1 就是 {66,55,44,33,22,11}
1.4 数组添加
1. 创建一个新的数组,比原来数组容量大 1 ,前面的元素拷贝过去,再添加最后的元素。
Scanner myScanner = new Scanner(System.in);
int[] arr = {1, 2, 3};
do{
int[] arrNew = new int[arr.length + 1];
for(int i=0; i<arr.length; i++){ //遍历arr数组,依次将arr的元素拷贝到arrNew数组
arrNew[i] = arr[i];
}
System.out.println("请输入你要添加的新元素");
int addNum = myScanner.nextInt();
arrNew[arrNew.length - 1] = addNum; //添加新元素
arr = arrNew; //让arr指向arrNew
for(int i = 0; i < arr.length; i++){ //输出扩容后的数组
System.out.print(arr[i] + "\t");
}
System.out.println("是否继续添加 y/n ");
char key = myScanner.next().charAt(0);
if(key == 'n'){
break;
}
}while(true);
2. 排序
排序是将多个数据,依指定的顺序进行排列的过程。
排序的分类:
- 内部排序:将需要处理的所有数据都加载到内部存储器中进行排序。包括——交换式排序法、选择式排序法和插入式排序法
- 外部排序:数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。包括——合并排序法和直接合并排序法
2.1. 冒泡排序
冒泡排序(Bubble Sorting)的基本思想是:通过对待排序序列从后往前(从下标较大的元素开始),依次比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从前移向后部,就像水底下的气泡逐渐向上冒一样。
2.2 思想分析
数组:[24, 69, 80, 57, 13]
第一轮排序:把最大的数放在最后面
第 1 次排序:[24, 69, 80, 57, 13]
第 2 次排序:[24, 69, 80, 57, 13]
第 3 次排序:[24, 69, 57, 80, 13]
第 4 次排序:[24, 69, 57, 13, 80]
第二轮排序:把第二大的数放在后面
第 1 次排序:[24, 69, 57, 13, 80]
第 2 次排序:[24, 57, 69, 13, 80]
第 3 次排序:[24, 57, 13, 69, 80]
第三轮排序:把第三大的数放在后面
第 1 次排序:[24, 57, 13, 69, 80]
第 2 次排序:[24, 13, 57, 69, 80]
第四轮排序:把第四大的数放在后面
第 1 次排序:[13, 24, 57, 69, 80]
总结:
-
一共 5 个元素,进行了 4 轮比较,可以看成外层循环。
-
每一轮排序可以确定一个数的位置,比如第一轮确定了最大数的位置。
-
比较过程中,如果前面的数大于后面的数,就交换。
-
每一轮比较都在减小:4-3-2-1
2.3 代码
int[] arr = {24, 69, 80, 57, 13};
for(int i = 1; i < arr.length; i++){
System.out.println("=====第" + i + "轮排序=====");
for(int j = 0; j < arr.length - i; j++){
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
for(int m = 0; m < arr.length; m++){
System.out.print(arr[m] + "\t");
}
System.out.println();
3.查找
3.1 顺序查找
代码:
String[] names = {"北京", "上海", "广州", "成都", "深圳"};
Scanner myScanner = new Scanner(System.in);
System.out.println("请输入一个城市名:");
String findName = myScanner.next();
int index = -1; //设置一个标志位,用于表示找到没有
for(int i = 0; i < names.length; i++){
//比较两个字符串是不是相等 "一个字符串".equals("另一个字符串")
if(names[i].equals(findName)){
System.out.println("已经找到城市名字:" + names[i]);
System.out.println("下标为:" + i);
index = 1;
break;
}
}
if(index == -1){
System.out.println("没有找到该城市!");
}
4. 多维数组(只介绍二维数组)
4.1 代码
int[][] arr = {{1,2,3}, {4,5,6}, {7,8,9}};
for(int i = 0; i < arr.length; i++){
for(int j = 0; j < arr[i].length; j++){
System.out.print(arr[i][j] + "\t");
}
System.out.println();
}
4.2 二维数组的初始化
-
动态初始化方式1:类型[][] 数组名 = new 类型[大小][大小],如:
int arr[][] = new int[2][3] //相当于定义了一个2行3列的矩阵,没有赋值,默认每个值为0
-
动态初始化方式2:
int arr[][]; //先声明二维数组 arr = new int[2][3]; //再开辟空间
-
动态初始化方式3(列数不确定):
int[][] arr = new int[3][]; //创建一个二维数组,一共有3个一维数组,只确定了一维数组的个数,还没有开辟空间 for(int i = 0; i < arr.length;i++){ arr[i] = new int[i + 1]; //给每一个一维数组开辟空间 new;如果没有给一维数组 new ,则arr[i]就是null for(int j = 0; j < arr[i].length; j++){ arr[i][j] = i + 1; //遍历一维数组,并给一维数组的每个元素赋值 } } //输出arr的元素 System.out.println("=====arr元素====="); for(int i = 0; i < arr.length; i++){ for(int j = 0; j < arr[i].length; j++){ System.out.print(arr[i][j] + " "); } System.out.println(); } /* 输出如下: 1 2 2 3 3 3 */
-
静态初始化:类型 数组名[][] = {{值1,值2,…},{值1, 值2,…},{值1, 值2,…}};如:
int[][] arr = {{1,2,3},{4,5,6},{50}} //最后一个一维数组只有一个元素,但是不能去掉{},有{}表示是一维数组,二维数组 //的基本元素只能是一维数组
4.3 杨辉三角形
//分析:1.第n行有n个元素
2.每一行的第一个元素和最后一个元素都是1
3.每一行除去首尾两个元素,中间的元素有 arr[i][j] = arr[i-1][j-1] + arr[i-1][j]
int[][] arr = new int[10][]; //定义了一个有10个一维数组的二维数组
for(int i = 0; i < arr.length; i++){
arr[i] = new int[i+1]; //为每一个一维数组开辟空间(1.第n行有n个元素)
for(int j = 0; j < arr[i].length; j++){
if(j == 0 || j == arr[i].length - 1){ //判断是不是收尾元素(2.每行的第一个元素和最后一个元素都是1)
arr[i][j] = 1;
}else{
arr[i][j] = arr[i-1][j-1] + arr[i-1][j]; //非首尾元素:arr[i][j]= arr[i-1][j-1]+arr[i-1][j]
}
}
}
System.out.println("======输出杨辉三角形=======");
for(int i = 0; i < arr.length; i++){
for(int j = 0; j < arr[i].length; j++){
System.out.print(arr[i][j] + "\t");
}
System.out.println();
}
输出如下:
4.4 二维数组注意事项
-
二维数组还有一种声明方式:int[] arr[]
-
二维数组的本质是由多个一维数组组成的,它的各个一维数组的长度可以不相同
5. 本章作业