数组属于引用类型的变量。数组的元素,既可以是基本数据类型,也可以是引用数据类型。
创建数组对象会在内存中开辟一整块连续的空间
数组的长度一旦确定,就不能修改
数组是有序排列的
1.初始化和长度
//1.1静态初始化:数组的初始化和数组元素的赋值操作同时进行 int[] ids = new int[]{1001,1002,1003,1004}; //1.2动态初始化:数组的初始化和数组元素的赋值操作分开进行 String[] names = new String[5]; //长度 names.length
2.数组元素的默认初始化值
数组元素是整形:0 数组元素是浮点型:0.0 数组元素是char型:0或'\u0000',而非'0' 数组元素是boolean型:false 数组元素是引用数据类型:null
一维数组的内存解析
int[] arr = new int[]{1,2,3}; String[] arr1 = new String[4]; arr1[1] = “刘德华”; arr1[2] = “张学友”; arr1 = new String[3]; System.out.println(arr1[1]);//null
初始化
//静态初始化 int[][] arr1 = new int[][]{{1,2,3},{4,5,6},{7,8,9}}; //动态初始化1 String[][] arr2 = new String[3][2]; //动态初始化2 String[][] arr3 = new String[3][]; //也正确 int[][] arr4 = {{1,2,3},{4,5,6},{7,8,9}};//类型推断
长度
int[][] arr = {{1,2,3},{4,5,6,7},{8,9,10}}; system.out.println(arr.length);//3,只看外层 system.out.println(arr[1].length);//4,内层
针对于初始化方式一:比如:int[][] arr = new int[4][3]; 外层元素的初始化值为:地址值 内层元素的初始化值为:与一维数组初始化情况相同 针对于初始化方式而:比如:int[][] arr = new int[4][]; 外层元素的初始化值为:null 内层元素的初始化值为:不能调用,否则报错。 int[][] arr = new int[4][3]; System.out.println(arr);//[[I@2b71fc7e 二维int型的地址 System.out.println(arr[0]);//[I@5ce65a89 一维int型的地址 System.out.println(arr[0][0]);//0
示例
int[][] arr1 = new int[4][]; arr1[1] = new int[]{1,2,3}; arr1[2] = new int[4]; arr1[2][1] = 30;
代码1
/* * 使用二维数组打印一个 10 行杨辉三角 * 1. 第一行有 1 个元素, 第 n 行有 n 个元素 * 2. 每一行的第一个元素和最后一个元素都是 1 * 3. 从第三行开始, 对于非第一个元素和最后一个元素的元素。 * 即:yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j]; */ public class YangHuiTest { public static void main(String[] args) { int[][] yangHui = new int[10][]; for(int i = 0;i < yangHui.length;i++){ yangHui[i] = new int[i + 1]; yangHui[i][0] = yangHui[i][i] = 1; for(int j = 1;j < yangHui[i].length - 1;j++){ yangHui[i][j] = yangHui[i-1][j-1] + yangHui[i-1][j]; } } for(int i = 0;i < yangHui.length;i++){ for(int j = 0;j< yangHui[i].length;j++){ System.out.print(yangHui[i][j] + " "); } System.out.println(); } } }
代码2
/* *创建一个长度为 6 的 int 型数组,要求取值为 1-30,同时元素值各不相同 */ public class RandomArray { public static void main(String[] args) { // 方式一: // int[] arr = new int[6]; // for (int i = 0; i < arr.length; i++) {// [0,1) [0,30) [1,31) // arr[i] = (int) (Math.random() * 30) + 1; // // boolean flag = false; // while (true) { // for (int j = 0; j < i; j++) { // if (arr[i] == arr[j]) { // flag = true; // break; // } // } // if (flag) { // arr[i] = (int) (Math.random() * 30) + 1; // flag = false; // continue; // } // break; // } // } // // for (int i = 0; i < arr.length; i++) { // System.out.println(arr[i]); // } // 方式二: int[] arr2 = new int[6]; for (int i = 0; i < arr2.length; i++) { arr2[i] = (int) (Math.random() * 30) + 1;// [0,1) [0,30) [1,31) for (int j = 0; j < i; j++) { if (arr2[i] == arr2[j]) { i--; break; } } } for (int i = 0; i < arr2.length; i++) { System.out.println(arr2[i]); } } }
代码3
/* * 回形数格式方阵的实现 * 从键盘输入一个整数(1~20) * 则以该数字为矩阵的大小,把 1,2,3…n*n 的数字按照顺时针螺旋的形式填入其中。例如: 输入数字2,则程序输出: 1 2 * 4 3 * 输入数字 3,则程序输出:1 2 3 * 8 9 4 * 7 6 5 * 输入数字 4, 则程序输出: * 1 2 3 4 * 12 13 14 5 * 11 16 15 6 * 10 9 8 7 */ public class ArrayTest { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("输入一个数字:"); int len = scanner.nextInt(); int[][] arr = new int[len][len]; int s = len * len; /* * k = 1:向右 k = 2:向下 k = 3:向左 k = 4:向上 */ int k = 1; int i = 0, j = 0; for (int m = 1; m <= s; m++) { if (k == 1) { if (j < len && arr[i][j] == 0) { arr[i][j++] = m; } else { k = 2; i++; j--; m--; } } else if (k == 2) { if (i < len && arr[i][j] == 0) { arr[i++][j] = m; } else { k = 3; i--; j--; m--; } } else if (k == 3) { if (j >= 0 && arr[i][j] == 0) { arr[i][j--] = m; } else { k = 4; i--; j++; m--; } } else if (k == 4) { if (i >= 0 && arr[i][j] == 0) { arr[i--][j] = m; } else { k = 1; i++; j++; m--; } } } // 遍历 for (int m = 0; m < arr.length; m++) { for (int n = 0; n < arr[m].length; n++) { System.out.print(arr[m][n] + "\t"); } System.out.println(); } } }
[a, b]的随机数公式:(int)(Math.random() * (b - a + 1) + a)
如[10,99],则是math.random() * 90 + 10
/* * 使用简单数组 * (1)创建一个名为 ArrayTest 的类,在 main()方法中声明 array1 和 array2 两个变量,他们是 int[]类型的数组。 * (2)使用大括号{},把 array1 初始化为 8 个素数:2,3,5,7,11,13,17,19。 * (3)显示 array1 的内容。 * (4)赋值 array2 变量等于 array1,修改 array2 中的偶索引元素,使其等于索引值(如 array[0]=0,array[2]=2)。打印出 array1。 */ public class ArrayTest2 { public static void main(String[] args) { //声明 array1 和 array2 两个 int[]变量 int[] array1,array2; //array1 初始化 array1 = new int[]{2,3,5,7,11,13,17,19}; //显示 array1 的内容==遍历。 for(int i = 0;i < array1.length;i++){ System.out.print(array1[i] + "\t"); } //赋值 array2 变量等于 array1 //不能称作数组的复制。 array2 = array1; //修改 array2 中的偶索引元素,使其等于索引值(如array[0]=0,array[2]=2) for(int i = 0;i < array2.length;i++){ if(i % 2 == 0){ array2[i] = i; } } System.out.println(); //打印出 array1 for(int i = 0;i < array1.length;i++){ System.out.print(array1[i] + "\t"); } } }
观察结果发现虽然改动的是array2,但array1内的数据也发生改变,这是因为array2 = array1的语句导致array1 和 array2 地址值相同,都指向了堆空间的唯一的一个数组实体,这是赋值操作,下面才是复制
//数组的复制 array2 = new int[array1.length]; for(int i = 0;i < array2.length;i++){ array2[i] = array1[i]; }
//方法一: for(int i = 0;i < arr.length / 2;i++){ String temp = arr[i]; arr[i] = arr[arr.length - i - 1]; arr[arr.length - i - 1] = temp; } //方法二: for(int i = 0,j = arr.length - 1;i < j;i++,j--){ String temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; }
线性查找
字符串的相等比较用equals()
String dest = "BB"; //要查找的元素 boolean isFlag = true; for(int i = 0;i < arr.length;i++){ if(dest.equals(arr[i])){ System.out.println("找到了指定元素,位置为:" + i); isFlag = false; break; } } if(isFlag){ System.out.println("很遗憾,没找到!"); }
二分法查找
前提是有序
int[] arr2 = new int[]{-98,-34,2,34,54,66,79,105,210,333}; int dest1 = -34; int head = 0; //初始的首索引 int end = arr2.length - 1; //初始的末索引 boolean isFlag1 = true; while(head <= end){ int middle = (head + end)/2; if(dest1 == arr2[middle]){ System.out.println("找到了指定元素,位置为:" + middle); isFlag1 = false; break; }else if(arr2[middle] > dest1){ end = middle - 1; }else{ head = middle + 1; } } if(isFlag1){ System.out.println("很遗憾,没找到!"); }
2.6.5.1 衡量排序算法的优劣
时间复杂度:分析关键字的比较次数和记录的移动次数
空间复杂度:分析排序算法中需要多少辅助内存
稳定性:若两个记录 A 和 B 的关键字值相等,但排序后 A、B 的先后次序保持不变,则称这种排序算法是稳定的。
2.6.5.2 十大内部排序算法
分类
选择排序
直接选择排序、堆排序
交换排序
冒泡排序、快速排序
插入排序
直接插入排序、折半插入排序、希尔排序
归并排序
桶式排序
基数排序
性能对比
2.6.5.3 冒泡排序
基本思想:
通过对待排序序列从前向后,依次比较相邻元素的排序码,若发现逆序则交换,使排序码较大的元素逐渐从前部移向后部。
for(int i = 0;i < arr.length - 1;i++){ for(int j = 0;j < arr.length - 1 - i;j++){ if(arr[j] > arr[j+1]){ int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } }
2.6.5.4 快速排序
基本思想
从数列中挑出一个元素,称为"基准"(pivot),
重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
/** * 快速排序 * 通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分关键字小, * 则分别对这两部分继续进行排序,直到整个序列有序。 * */ public class QuickSort { private static void swap(int[] data, int i, int j) { int temp = data[i]; data[i] = data[j]; data[j] = temp; } private static void subSort(int[] data, int start, int end) { if (start < end) { int base = data[start]; int low = start; int high = end + 1; while (true) { while (low < end && data[++low] - base <= 0) ; while (high > start && data[--high] - base >= 0) ; if (low < high) { swap(data, low, high); } else { break; } } swap(data, start, high); subSort(data, start, high - 1);//递归调用 subSort(data, high + 1, end); } } public static void quickSort(int[] data){ subSort(data,0,data.length-1); } public static void main(String[] args) { int[] data = { 9, -16, 30, 23, -30, -49, 25, 21, 30 }; System.out.println("排序之前:\n" + java.util.Arrays.toString(data)); quickSort(data); System.out.println("排序之后:\n" + java.util.Arrays.toString(data)); } }
java.util.Arrays类即为操作数组的工具类,包含了用来操作数组(比如排序和搜索)的各种方法。
1 | boolean equals(int[] a,int[] b) | 判断两个数组是否相等。 |
---|---|---|
2 | String toString(int[] a) | 输出数组信息。 |
3 | void fill(int[] a,int val) | 将指定值填充到数组之中。 |
4 | void sort(int[] a) | 对数组进行排序。 |
5 | int binarySearch(int[] a,int key) | 对排序后的数组进行二分法检索指定的值。 |
代码示例
//1.boolean equals(int[] a,int[] b)判断两个数组是否相等。 int[] arr1 = new int[]{1,2,3,4}; int[] arr2 = new int[]{1,2,9,3}; boolean isEquals = Arrays.equals(arr1, arr2); System.out.println(isEquals); //2.String toString(int[] a)输出数组信息。 System.out.println(Arrays.toString(arr1)); //3.void fill(int[] a,int val)将指定值填充到数组之中。 Arrays.fill(arr1, 10); System.out.println(Arrays.toString(arr1));//[10 10 10 10] //4.void sort(int[] a)对数组进行排序。 Arrays.sort(arr2); System.out.println(Arrays.toString(arr2)); //5.int binarySearch(int[] a,int key)对排序后的数组进行二分法检索指定的值。 int[] arr3 = new int[]{-98,-34,2,34,56,78,100,210,485}; int index = Arrays.binarySearch(arr3, 210);//返回负数就是没找到 if(index >= 0){ System.out.println(index); }else{ System.err.println("未找到。");
数组中的常见异常:
数组角标越界的异常:ArrayIndexOutOfBoundsException
空指针异常:NullPointerException
示例
//1.数组角标越界的异常:ArrayIndexOutOfBoundsException int[] arr = new int[]{1,2,3,4,5,6}; //错误1: for(int i = 0;i <= arr.length;i++){ System.out.println(arr[i]); } //错误2: System.out.println(arr[-2]); //2.空指针异常:NullPointerException //情况一: int[] arr2= new int[]{1,2,3}; arr2 = null; System.out.println(arr2[0]); //情况二: int[][] arr2 = new int[4][]; System.out.println(arr2[0][0]); //情况三: String[] arr3 = new String[]{"AA","QQ","YY","XX","TT","KK"}; arr3[0] = null; System.out.println(arr3[0].toString()); //调用null的方法,所以空指针