想存储一个班50名学生的成绩难道要定义50个变量吗想把一组数据按从小到大排列该怎么做想在一个数组里快速找到某个元素有什么高效的方法答案就在今天的主题里——数组、排序和查找。本文将从数组的基本概念入手逐步讲解数组的声明与使用再介绍经典的冒泡排序算法和二分查找算法。案例引导一个班里有 6 位尖子生它们的期末分数分别是 10099.5989593.592。求出他们的分数和与平均数传统方法public class Test { public static void main(String[] args) { //分数包含小数用 double 类型 double score1 100; double score2 99.5; double score3 98; double score4 95; double score5 93.5; double score6 92; //求分数和与平均分 double totalScore score1 score2 score3 score4 score5 score6; double avgScore totalScore / 6; System.out.println(6位尖子生的分数和为 totalScore 平均分为 avgScore); } }正如开篇引导的问题如果一个班 50 位学生用传统方法定义 50 个变量显然不现实这时需要数组方法解决问题数组介绍数组可以存放多个同一类型的数据。数组也是一种数据类型是引用类型。即数组就是一组数据数组方法public class Test { public static void main(String[] args) { //创建数组变量 //double[] 表示 double 类型的数组数组名叫 scores //{100, 99.5, 98, 95, 93.5, 92} 表示数组的元素值依次表示数组的第几个元素 double[] scores {100, 99.5, 98, 95, 93.5, 92}; double totalScore 0; double avgScore 0; //遍历数组求分数和 //通过下标scores[下标] 来访问数组的元素 //下标是从 0 开始编号如第 n 个元素的下标为 n - 1即 scores[n - 1] //数组名.length 表示数组的大小长度即数组中的元素个数本题中 scores.length 6 for(int i 0; i scores.length; i) { totalScore scores[i]; } //求平均数 avgScore totalScore / scores.length; System.out.println(6位尖子生的分数和为 totalScore 平均分为 avgScore); } }注意索引下标用于访问数组元素的编号第一个元素从 0 开始编号数组名.length表示数组的大小长度即数组中元素的个数数组的使用方式1. 动态初始化2. 静态初始化动态初始化数组的定义方式一语法数据类型[ ] 数组名 new 数据类型[大小];推荐也可以数据类型 数组名[ ] new 数据类型[大小];如int a[] new int[5]; //创建了一个数组名字为 a存放 5 个 int 变量方式二1. 先声明数组语法数据类型[ ] 数组名;推荐/ 也可以数据类型 数组名[ ];如int[ ] a; 或者 int a[ ];2. 创建数组语法数组名 new 数据类型[大小];如a new int[10];静态初始化数组的定义语法数据类型[ ] 数组名 {元素值, 元素值, ...};推荐也可以数据类型 数组名[ ] {元素值, 元素值, ...};如int[ ] a {2, 5, 9, 30, 56, 98}; / int a[ ] {2, 5, 9, 30, 56, 98};注意此定义方法适用于知道元素个数且有限有元素具体值的情况数组使用注意事项和细节1. 数组是多个相同类型数据的组合实现对这些数据的统一管理2. 数组中的元素可以是任何数据类型包括基本类型和引用类型但是不能混用double[] scores {100, 99.5, 98, 85, 93.5, 92}; boolean[] pass {true, false}; char[] lower {a, b, c, d, e}; String[] names {jack, milan, tom};3. 数组创建后如果没有赋值有默认值。int 0short 0byte 0long 0float 0.0double 0.0char \u0000boolean falseString nullshort[] nums new short[3]; for(int i 0; i nums.length; i) { System.out.print(nums[i] ); //0 0 0 }4. 使用数组的步骤(1). 声明数组并开辟空间(2). 给数组各个元素赋值(3). 使用数组5. 数组的下标是从 0 开始6. 数组的下标必须在指定范围内使用否则报下标越界异常int[] arr new int[5]; //有效下标为 0-4出现 5 及其以上会出现报错7. 数组属引用类型数组型数据是对象(object)数组基础练习练习一创建一个 char 类型的 26 个元素的数组分别放置 A-Z并打印遍历提示 char 类型数据运算 A 2 - Cpublic class ArrayExercise01 { //编写一个main方法 public static void main(String[] args) { //创建26字母数组 char[] c new char[26]; for(int i 0; i c.length; i) { //强制类型转换int - char c[i] (char)(A i); } //遍历 for(int j 0; j c.length; j) { System.out.print(c[j] ); } //A B C D E F G H I J K L M N O P Q R S T U V W X Y Z } }练习二请求出一个数组 int[ ] 的最大值 {4, -1, 9, 10, 23}并得到对应的下标public class ArrayExercise02 { //编写一个main方法 public static void main(String[] args) { //创建数组 int[] arr {4, -1, 9, 10, 23}; //定义最大值索引 int max arr[0]; //假设第一个元素为最大值 int maxIndex 0; //遍历寻找最大值 for(int i 1; i arr.length; i) { if(arr[i] max) { max arr[i]; maxIndex i; } } System.out.println(该数组的最大值为 max 对应的下标为 maxIndex); //23 4 } }数组的赋值机制1. 基本数据类型赋值这个值就是具体的数据而且相互不影响值传递public class ArrayAssign01 { //编写一个main方法 public static void main(String[] args) { //基本数据类型赋值 int n1 10; int n2 n1; n2 80; System.out.println(n1 n1); //10 System.out.println(n2 n2); //80 } }2. 数组在默认情况下引用传递赋的值是地址public class ArrayAssign02 { //编写一个main方法 public static void main(String[] args) { //引用传递 int[] arr1 {1, 2, 3}; int[] arr2 arr1; //把 arr1 赋给 arr2 //arr2 指向 arr1 的地址arr2 的变化会影响到 arr1 arr2[0] 10; System.out.println(arr1的元素); for(int i 0; i arr1.length; i) { System.out.println(arr1[ i ] arr1[i]); } /* arr1[0] 10 arr1[1] 2 arr1[2] 3 */ } }值传递值拷贝和引用传递地址拷贝的区别简单来说值传递拷贝的是一个具体的值而引用传递拷贝的是一个地址如0x0011数组拷贝public class ArrayCopy { //编写一个main方法 public static void main(String[] args) { //将 int arr1[] {10, 20, 30}; 拷贝到 arr2 数组要求数据空间是独立的 int[] arr1 {10, 20, 30}; //创建一个新的数组 arr2开辟新的数据空间大小为 arr1.length int[] arr2 new int[arr1.length]; int i 0; for(i 0; i arr1.length; i) { //值传递 arr2[i] arr1[i]; } //遍历数组 for(i 0; i arr1.length; i) { System.out.println(arr2[ i ] arr2[i]); } /* arr2[0] 10 arr2[1] 20 arr2[2] 30 */ } }数组反转数组反转就是将数组中的元素反过来表示。即最后一个元素放在第 1 个位置倒数第 2 个元素转置第 2 个位置以此类推案例演示将如下数组反转即arr {11, 22, 33, 44, 55, 66} -- {66, 55, 44, 33, 22, 11}此方法多样大致有三种解法解法一反向遍历输出非真正反转public class ArrayReverse { //编写一个main方法 public static void main(String[] args) { int[] arr {11, 22, 33, 44, 55, 66}; System.out.println(反转后); System.out.print(int[] arr {); //从最后一个元素的索引开始逐级递减 for(int i arr.length - 1; i 0; i--) { if(i ! 0) { System.out.print(arr[i] , ); } else { System.out.print(arr[i] };); } } //int[] arr {66, 55, 44, 33, 22, 11}; } }注此解法只是反向遍历并打印并没有真正修改原数组的内容若需要改动原数组此方法并不适用。解法二创建新数组public class ArrayReverse { //编写一个main方法 public static void main(String[] args) { int[] arr {11, 22, 33, 44, 55, 66}; System.out.println(反转后); System.out.print(int[] arr {); //创建新数组 int[] arr2 new int[arr.length]; for(int i arr.length-1, j 0; i 0; i--, j) { arr2[j] arr[i]; } //将 arr2 赋给 arr arr arr2; //遍历输出 for(int i 0; i arr.length; i) { if(i ! arr.length - 1) { System.out.print(arr[i] , ); } else { System.out.print(arr[i] };); } } //int[] arr {66, 55, 44, 33, 22, 11}; } }解法三双指针交换原地反转public class ArrayReverse { //编写一个main方法 public static void main(String[] args) { int[] arr {11, 22, 33, 44, 55, 66}; System.out.print(int arr[] {); int left 0, right arr.length - 1; //数组最左边和最右边交换 //11 - 66, 22 - 55, 33 - 44 while(left right) { //左右交换设置 temp 临时变量 int temp arr[left]; arr[left] arr[right]; arr[right] temp; //缩小边界 left; right--; } //遍历输出 for(int i 0; i arr.length; i) { if(i ! arr.length - 1) { System.out.print(arr[i] , ); } else { System.out.print(arr[i] };); } } //int[] arr {66, 55, 44, 33, 22, 11}; } }数组扩容要求实现动态的给数组添加元素效果实现对数组扩容(1). 原始数组使用静态分配 int[ ] arr {1, 2, 3}(2). 增加的元素直接放在数组的最后 arr {1,2 ,3, 4}public class ArrayAdd { //编写一个main方法 public static void main(String[] args) { int[] arr {1, 2, 3}; //创建新数组 int[] arr2 new int[arr.length 1]; //给新数组赋值 for(int i 0; i arr.length; i) { arr2[i] arr[i]; } arr2[arr.length] 4; //将 arr2 赋给 arr arr arr2; //遍历输出 System.out.print(新添加的数组 arr[] {); for(int i 0; i arr.length; i) { if(i ! arr.length - 1) { System.out.print(arr[i] , ); } else { System.out.print(arr[i] };); } } //新添加的数组 arr[] {1, 2, 3, 4}; } }(3). 用户可以通过如下方法来决定是否继续添加。添加成功是否继续y / nimport java.util.Scanner; public class ArrayAdd02 { //编写一个main方法 public static void main(String[] args) { Scanner scanner new Scanner(System.in); int[] arr {1, 2, 3}; char answer; //是否继续添加 //添加新元素 do { int[] arr2 new int[arr.length 1]; for(int i 0; i arr.length; i) { arr2[i] arr[i]; } System.out.print(请输入你要添加的元素); arr2[arr.length] scanner.nextInt(); arr arr2; System.out.print(新添加的数组 arr[] {); for(int i 0; i arr.length; i) { if(i ! arr.length - 1) { System.out.print(arr[i] , ); } else { System.out.print(arr[i] };); } } System.out.println(); System.out.print(添加成功是否继续添加); answer scanner.next().charAt(0); } while(answer y); System.out.println(你退出了添加...); } }数据缩减要求有一个数组 {1, 2, 3, 4, 5}可以将该数组进行缩减提示用户是否继续缩减没次缩减最后哪个元素当只剩下最后一个元素提示不能再缩减public class ArrayReduce { //编写一个main方法 public static void main(String[] args) { int[] arr {1, 2, 3, 4, 5}; int len arr.length; //数组长度 int reduce_count 0; //缩减次数 while(len ! 1) { reduce_count; //创建新数组 int[] arr2 new int[arr.length - 1]; for(int i 0; i arr.length - 1; i) { arr2[i] arr[i]; } //将 arr2 赋给 arr arr arr2; System.out.print(第 reduce_count 次缩减所得的数组为 {); for(int i 0; i arr.length; i) { if(i ! arr.length - 1) { System.out.print(arr[i] , ); } else { System.out.print(arr[i] }); } } System.out.println(); //缩减数组长度 len--; if(len ! 1) { System.out.println(用户可以继续缩减); } else { System.out.println(不能再缩减); } } } }排序介绍排序是将一群数据依指定的顺序进行排列的过程排序的分类1. 内部排序指将需要处理的所有数据都加载到内部存储器中进行排序。包括交换式排序法、选择式排序法和插入式排序法2. 外部排序数据量过大无法全部加载到内存中需要借助外部存储进行排序。包括合并排序法和直接合并排序法冒泡排序法冒泡排序的基本思想是通过对待排序序列从后向前从下标较大的元素开始依次比较相邻元素的值若发现逆序则交换使值较大的元素逐渐从前部移向后部就像水底下的气泡一样逐渐向上冒案例分析分析冒泡排序将数组 arr[5] {21, 54, 96, 36, 15} 用冒泡排序方法升序排序第1轮排序目标把最大数放在最后第1次比较 {21, 54, 96, 36, 15}arr[0] 与 arr[1] 比较第2次比较 {21, 54, 96, 36, 15}arr[1] 与 arr[2] 比较第3次比较 {21, 54, 36, 96, 15}arr[2] 与 arr[3] 比较第4次比较 {21, 54, 36, 15,96}arr[3] 与 arr[4] 比较第2轮排序目标把第2大数放在倒数第2位置第1次比较 {21, 54, 36, 15,96}arr[0] 与 arr[1] 比较第2次比较 {21, 36, 54, 15,96}arr[1] 与 arr[2] 比较第3次比较 {21, 36, 15,54, 96}arr[2] 与 arr[3] 比较第3轮排序目标把第3大数放在倒数第3位置第1次比较 {21, 36, 15,54, 96}arr[0] 与 arr[1] 比较第1次比较 {21, 15,36, 54, 96}arr[1] 与 arr[2] 比较第4轮排序目标把第4大数放在倒数第4位置第1次比较 {15,21, 36, 54, 96}arr[0] 与 arr[1] 比较总结冒泡排序特点1. 一共有 5 个元素2. 一共进行了 4 轮排序3. 每一轮排序可以确定一个数的位置比如第 1 轮排序确定最大数第 2 轮排序确定第 2 大数的位置以此类推4. 当进行比较时如果前面的数大于后面的数就交换5. 每轮比较次数在减少4 - 3 - 2 - 1代码实现//冒泡排序 public class BubbleSort { //编写一个main方法 public static void main(String[] args) { int[] arr {21, 54, 96, 36, 15}; //嵌套 for 循环进行冒泡排序比较 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]) { //设置临时变量 temp用于辅助交换 int temp arr[j]; arr[j] arr[j 1]; arr[j 1] temp; } } } System.out.print(排序后的数组为 arr[] {); for(int i 0; i arr.length; i) { if(i ! arr.length - 1) { System.out.print(arr[i] , ); } else { System.out.println(arr[i] };); } } //排序后的数组为 arr[] {15, 21, 36, 54, 96}; } }查找介绍在 Java 中常用的查找有两种(1). 顺序查找(2). 二分查找案例演示顺序查找有一个数组东岳泰山、西岳华山、北岳恒山、南岳衡山、中岳嵩山。从键盘中任意输入一个名称判断数列中是否包含此名称。要求如果找到就提示找到了并给出下标值否则提示未找到//顺序查找 import java.util.Scanner; public class SeqSearch { //编写一个main方法 public static void main(String[] args) { //创建字符串数组 String[] hills {东岳泰山, 西岳华山, 北岳恒山, 南岳衡山, 中岳嵩山}; Scanner scanner new Scanner(System.in); System.out.print(请输入名称); String name scanner.next(); int found 0; //是否找到 int Index 0; //名称下标 for(int i 0; i hills.length; i) { if(name.equals(hills[i])) { found 1; //找到了 Index i; break; } } //判断是否找到 if(found 1) { System.out.println(恭喜你找到了其下标为 Index); } else { System.out.println(很遗憾未找到此名称); } } }二分查找请对一个有序数组进行二分查找 {1, 8, 30, 89, 1000, 1234}输入一个数看看该数组是否存在此数若有则给出下标若没有就提示“没有这个数”二分查找也称折半查找每次查找取中间位置通过将查找范围缩小一半的方式在有序数组中快速定位目标元素的位置import java.util.Scanner; public class BinarySearch { //编写一个main方法 public static void main(String[] args) { int[] arr {1, 8, 30, 89, 1000, 1234}; Scanner scanner new Scanner(System.in); System.out.print(请输入要查找的数); int target scanner.nextInt(); //要查找的数必须是 arr 数组里的 //定义数组左右边界 int left 0; int right arr.length - 1; int index -1; //初始化为 -1表示未找到 while (left right) { //取中间位置查找 int mid (left right) / 2; if (target arr[mid]) { index mid; break; } else if (target arr[mid]) { left mid 1; //向右半部分查找 } else { right mid - 1; //向左半部分查找 } } if (index ! -1) { System.out.println(找到了目标值 target 的下标是 index); } else { System.out.println(没有这个数); } } }小结数组是 Java 中存储多个相同类型数据的容器通过下标索引可以快速访问每一个元素排序让无序的数据变得有规律查找则让我们能在数据中快速定位目标。本文介绍的冒泡排序和二分查找是算法入门的经典内容虽然它们在实际开发中可能被封装好的工具类所替代但背后的思想——比较与交换、分而治之——是理解更复杂算法的基础。希望小伙伴在学习的时候能亲手敲一遍代码感受数据在内存中如何一步步变得有序以及在有序数组中如何高效地“折半”缩小范围。掌握了这些基本功后续学习数据结构和算法等更高级的知识才会更加从容。关于数组的内容的学习还未结束下期我们来聊聊二维数组的学习与使用。