07 Java数组与数组操作(定义+遍历+排序+增删改查)(上):https://developer.aliyun.com/article/1580194
7.7.2 选择排序
选择排序升序思路:
- 1、将当前这个数,与他后面每一个数字比较,选择最小的那个数,交换到当前位置
- 2、循环选择当前位置上的数
public static int[] sort1(int[] arr) { for (int j = 0; j < arr.length-1; j++) { //选择下标为0的位置 int min = j; //将当前这个数与后面的每一个数进行比较 for (int i = j+1; i < arr.length; i++) { if(arr[min] > arr[i]) { min = i; } } //arr[j] arr[min] if(min != j) { int temp = arr[j]; arr[j] = arr[min]; arr[min] = temp; } } return arr; }
细分示例:
public class newArray { //选择排序 public static void selectSort(int[] arr){ //外层循环控制轮数 for (int i = 0; i < arr.length-1; i++) { int min=i;//保存最小元素的下标 for (int j = i+1; j < arr.length; j++) { if(arr[j]<arr[min]){ min=j;//最小的下标 } } if(min!=i){ int t=arr[i]; arr[i]=arr[min]; arr[min]=t; } } } }
7.7.3 Arrays工具类排序方法
public class Demo03 { //Arrays类提供的数组排序的方法 public static void main(String[] args) { int[] arr = {11,22,33,31,41,15}; //Arrays类提供的数组排序的方法 快速排序 Arrays.sort(arr); for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } System.out.println("=============================================="); String[] names = {"cxk","rose","lihua","lilei","zhaosi"}; Arrays.sort(names); for (int i = 0; i < names.length; i++) { System.out.print(names[i]+"\t"); } } }
API 工具类
Arrays工具类的使用
public class Demo { public static void main(String[] args) { int[] nums={15,10,3,20,13,1,20,35,39,28,18,22}; //1 排序 Arrays.sort(); Arrays.sort(nums); //2 字符串形式 Arrays.toString(); String s=Arrays.toString(nums); System.out.println(s); //3 二分查找 int pos=Arrays.binarySearch(nums,1); System.out.println(pos>=0?"找到了":"没有找到"); //4 复制数组 int[] newArr=Arrays.copyOf(nums,nums.length*2); System.out.println(Arrays.toString(newArr)); //截取数组前num项 int[] newArr= Arrays.copyOf(nums,5); System.out.println(Arrays.toString(newArr)); //5 填充,fill Arrays.fill(nums,100); System.out.println(Arrays.toString(nums)); } }
补充 JDK API 1.6
7.8 二分查找法
二分查找法(折半查找法)
- 前提:数组中的元素是有序的
- 思路
- 首先找到数组中的中间的元素,与要查找元素进行比较,如果相等,那么就直接找到了
- 如果比中间的元素大,那么表示查找元素在中间值的右边。所以最小值的下标等于中间值的下标+1
- 如果比中间的元素小,那么表示查找元素在中间值的左边。所以最大值的下标等于中间值的下标-1
//二分查找法 public static int search2(int[] arr,int num) { //1、获取最小、大值的下标 int min = 0; int max = arr.length -1; while(min <= max) { //2、获取中间值的下标 int middle = (min + max) / 2; //3、将要查找的数字与中间值做比较 if(num > arr[middle]) { min = middle +1; }else if(num < arr[middle]) { max = middle -1; }else { return middle; } } return -1; }
对比:顺序查找与二分查找
import java.util.Scanner; public class Demo { public static void main(String[] args) { Scanner input=new Scanner(System.in); System.out.println("请输入您要查找的元素"); int n=input.nextInt(); //int pos=sequenceSearch(n); int pos=binarySearch(n); System.out.println(pos>=0?"找到了":"没有找到"); } //顺序查找:从第一个元素遍历到最后一个元素,查找符合要求的。 public static int sequenceSearch(int key){ int[] arr=new int[]{15,2,8,20,3,28,30,16,22}; for (int i = 0; i < arr.length; i++) { if(key==arr[i]){ return i; } } return -1; } //二分查找:二分查找前提,数组是有序的。 //每次从中间开始查找,如果比中间数字小,在左边查找,如果比中间数字大,在右边查找,依次再进行二分查找,直到找到为止。 public static int binarySearch(int key){ int[] arr=new int[]{1,3,5,8,10,15,22,23,25,30,35,50,55,60}; int low=0; int upper=arr.length-1; while(low<=upper){ int mid=(low+upper)>>>1; if(key<arr[mid]){ upper=mid-1; }else if(key>arr[mid]){ low=mid+1; }else{ return mid; } } return -1; } }
7.9 二维数组
- 一维数组中的每一个元素,存储的是一个数据
- 二维数组中的每一个元素,存储的是一个一维数组
public class newArray { public static void main(String[] args) { //声明二维数组 int[][] nums1=new int[][]{ {10,20,30},{40,50,60} }; int[][] nums2=new int[2][3];// 第一维数组长度是2, 第二维数组长度是3 nums2[0][0]=100; nums2[0][1]=200; nums2[0][2]=300; nums2[1][0]=400; nums2[1][1]=500; nums2[1][2]=600; //输出数组长度 System.out.println(nums2.length); System.out.println(nums2[0].length); System.out.println(nums2[1].length); //遍历二维数组 for (int i = 0; i < nums2.length; i++) { //第一维数组 for (int j = 0; j < nums2[i].length; j++) { //第二维数组 System.out.print(nums2[i][j]+"\t"); } System.out.println(); } //创建不规则的二维数组 int[][] nums3=new int[][]{{5,6,10},{3,20,22,50,80}}; int[][] nums4=new int[2][]; //第一维长度是2, 每个元素null nums4[0]=new int[]{5,6,10}; nums4[1]=new int[]{3,20,22,50,80}; } } // 2 // 3 // 3 // 100 200 300 // 400 500 600
7.9.1 创建二维数组
静态初始化:
- 语法1:数据类型[][] 数组名 = {{元素1,元素2,…},{元素1,元素2,…},…};
- 语法2:数据类型[][] 数组名 = new 数据类型[][]{{元素1,元素2,…},{元素1,元素2,…},…};
动态初始化
- 语法:数据类型[][] 数组名 = new 数据类型[ 二维数组的长度] [一维数组的长度];
- 注意:二维数组的长度必须要定义,一维数组的长度可以暂时不定义
7.9.2 二维数组的使用
int[][] arr = new int[3][]; //操作数组 存储或者获取 //注意:在使用之前必须先要对一维数组进行初始化 //arr[0][0] = 11;错误 arr[0] = new int[2]; arr[0][0] = 11; arr[0][1] = 22; arr[1] = new int[1]; arr[1][0] = 33; arr[2] = new int[3]; arr[2][0] = 44; arr[2][1] = 55; arr[2][2] = 66; //获取二维数组的长度 System.out.println(arr.length);
7.9.3 二维数组的遍历
//二维数组的遍历 for (int i = 0; i < arr.length; i++) { for (int j = 0; j < arr[i].length; j++) { System.out.println(arr[i][j]); } }
7.9.4 二维数组的应用
用二维数组实现杨辉三角
// 使用二维数组实现杨辉三角 public class Demo { public static void main(String[] args) { rectangle(); } public static void rectangle(){ int[][] arr=new int[5][]; for (int i = 0; i < arr.length; i++) { arr[i]=new int[i+1];//第二维数组初始化 //空格 %s System.out.printf() //元素赋值 for (int j = 0; j < arr[i].length; j++) { if(j==0||i==j){ arr[i][j]=1; }else{ arr[i][j]=arr[i-1][j-1]+arr[i-1][j]; } System.out.print(arr[i][j]);//输出 } System.out.println(); } } }
7.10 可变参数
可变参数:jdk1.5之后的新语法
语法: 数据类型… 参数名
特点:
- 1、带有可变参数方法的调用的时候,实参个数,可以是0个或者是多个
- 2、可变参数只能放在参数列表的最后(一个方法只能有一个可变参数)
- 3、可变参数可以当做数组来使用,也可以将数组作为参数
场景:不确定参数个数的时候
案例:根据用户传入的数字,进行求和,数字个不确定
//案例:根据用户传入的数字,进行求和,数字个不确定 public static int sum(int... arr) { int sum = 0; for (int i = 0; i < arr.length; i++) { sum = sum + arr[i]; } return sum; }
可变长参数
public class newArray { public static void main(String[] args) { //传递数组元素 printArry(100,22,33,44,55,66); } //可变长参数:可接收多个同类型实参,个数不限,使用方式与数组相同。 //优点:比数组更加灵活 //要求:只能方法参数列表最后,只能有一个 public static void printArry(int x,int ...arr){ for (int i = 0; i < arr.length; i++) { System.out.print(arr[i]+"\t"); } } } //22 33 44 55 66
7.10.1 可变参数方法的定义
public static void m1(int... a) { System.out.println(a[0]); System.out.println(a[1]); }
7.10.2 带有可变参数方法的调用
//方式1 m1(1,2,3,4,5); //方式2: int[] arr = {1,2,3}; m1(arr);
7.11 值传递和应用传递
值传递和引用传递
- 值传递:传递的是值,所以原来的值本身不会改变,所有的基本类型+String都属于值传递
- 引用传递:传递的是地址,所以会对原来的内容有影响,所有引用数据类型都属于引用传递
public class Demo { public static void main(String[] args) { /* int x=10,y=20; swap(x,y); System.out.println("x:"+x+" y:"+y); */ int[] nums={80,82,85,79,75}; printArray(nums); System.out.println("--------------"); for (int num : nums) { System.out.println(num); } } //基本类型作为方法的参数 public static void swap(int a,int b){ System.out.println("交换前 a:"+a+" b:"+b); a=a^b; b=a^b; a=a^b; System.out.println("交换后 a:"+a+" b:"+b); } //数组作为方法的参数 public static void printArray(int[] arr){ for (int i = 0; i < arr.length; i++) { arr[i]=arr[i]+5; System.out.println(arr[i]); } } }
public class newArray { public static void main(String[] args) { int [] arr= {89,85,92,85,84,88}; arr = expand(arr); for (int i = 0; i < arr.length; i++) { System.out.print(arr[i]+"\t"); //89 85 92 85 84 88 0 0 0 0 0 0 } } //数组类型作为方法的返回值,数组扩容 public static int[] expand(int[] old){ //1.创建一个长度大于原数组的新数组 int[] newArray =new int[old.length*2]; //2.复制原数组数据 for (int i = 0; i < old.length; i++) { newArray[i]=old[i]; } //3.返回新数组地址 return newArray; } } //调用基本类型返回值的方法时,方法执行后,返回的是数据; // //调用引用类型返回值的方法时,方法执行后,返回的是地址
public class Demo { public static void main(String[] args) { //通过方法形式的传递 // int a = 10; // System.out.println("传递之前a的值为:"+a); // m1(a); // System.out.println("传递之后a的值为:"+a); // // String s = "hello"; // System.out.println("传递之前s的值为:"+s); // m2(s); // System.out.println("传递之后s的值为:"+s); // // double[] d = {1,2,3}; // System.out.println("传递之前d[0]的值为:"+d[0]); // m3(d); // System.out.println("传递之后d[0]的值为:"+d[0]); //通过变量形式的传递 int a = 10; int b = a; b = 20; System.out.println(a); String s = "a"; String s1 = s; s1 = "b"; System.out.println(s); int[] arr1 = {1,2,3}; int[] arr2 = arr1; arr2[0] = 100; System.out.println(arr1[0]); } public static void m1(int a) { a = 20; } public static void m2(String s) { s = "world"; } public static void m3(double[] d) { d[0] = 100; } }
7.12 数组的增删改查
7.12.1 增加数据
增加数据分为两种添加方式“一种叫做静态添加和一种叫做动态添加”
- 一般静态添加使用较少,它的操作还就是在数组的时候,直接数组中存储数据
int[] arr = new int[]{1,2,3,4,5,6,7}; int[] arr2 = {1,2,3,4,5,5,6,7};
动态添加,键盘输入数据、随机数、文件读取内容之后存储、数据库操作之后存储
键盘输入和随机数据使用较多
import java.util.Scanner; /** * @author yinying * @date 2023/1/10 12:21 * @poject JavaDemo */ public class newArray { public static void main(String[] args) { //定义一个int类型数组,数组的长度为10 int[] arr = new int[10]; //1.随机数赋值 for(int i = 0 ; i<arr.length;i++){ arr[i] = (int)(Math.random()*100); } //或者 //2.通过控制台输入 Scanner input = new Scanner(System.in); for(int i = 0 ; i<arr.length;i++){ arr[i] = input.nextInt(); } } }
7.12.2 查找和修改数据(转7.7.2)
数组中查找某个元素是否存在,一共有两种方式“线性(顺序)查找 和 二分(折半)查找”
单从效率而言“二分查找远远高于线性查找”,从书写代码而言“线性查找要远远简单于二分查找”线性(顺序)查找执行原理:就是从数组第一个元素逐一向后查找每一个元素
线性查找最优解 1次 【数组第一个元素就是要查找的元素】
线性查找最坏解 数组长度次数 【数组最后一个元素是要查找的元素】
线性查找最坏解 数组长度次数 【数组最后一个元素是要查找的元素】
线性查找最大有点就是简单易用,效率确实不高
import java.util.Arrays; import java.util.Scanner; /** * @author yinying * @date 2023/1/10 17:11 * @poject JavaDemo */ public class newArray { public static void main(String[] args) { //1.提供一个int类型数组,数组长度10 int[] arr = new int[10]; //2.通过随机数向数组中进行赋值操作 for(int i = 0 ; i<arr.length;i++) { arr[i] = (int) (Math.random() * 100); } 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]+"]"); } } System.out.println("请输入您要在arr数组中要查找的数据:"); Scanner input = new Scanner(System.in); int num = input.nextInt(); //提供线性(顺序)查找,判断要查找数据是否存在在当前的数组中 for(int i = 0 ;i<arr.length;i++){ if(arr[i] == num){ //提供修改 // arr[i] = 10000; //提示找到了数据 System.out.println("您输入数据是在数组中存储的下标为:"+i); return; } } System.out.println("没有找到数据"); } }
7.12.3 删除
在没有使用数组的“减容”之前,数组中是没有真正删除的
“减容”—根据删除元素个数动态缩小数组容量(大小/长度)
如何在数组中执行删除操作?
根据中存储元素类型来决定,如果数组中存储的是基本数据类型,采用后一个数据覆盖前一位数据的方式进行删除,并记录删除个数以便在打印时,可以不输出多余数据【这个操作不是”减容“,数组长度不会改变】,如果数组中存储的是引用数据类型,依旧会采用后一个数据覆盖前一个数据方式,会在最后一个数据位置添加 null值,或者直接要删除的赋值为null,并记录删除个数以便在打印中,不输出多余的数据。
package priv.yinying.javademo; import java.util.Arrays; import java.util.Scanner; /** * @author yinying * @date 2023/1/10 19:33 * @poject JavaDemo */ public class newArray { public static void main(String[] args) { //1.提供一个int类型数存储10个元素 int[] arr = new int [10]; //2.提供动态赋值同时打印数组中数据 System.out.print("arr数组中存储的数据["); for(int i = 0 ; i<arr.length;i++){ arr[i] = (int)(Math.random()*100); if(i != arr.length-1){ System.out.print(arr[i]+","); }else{ System.out.println(arr[i]+"]"); } } System.out.println("删除之前arr数组的长度:"+arr.length); //3.提供外界输入的数据进行删除操作 System.out.println("请输入您要删除的数据:"); Scanner input = new Scanner(System.in); int num = input.nextInt(); //提供一个变量存储删除数据的个数 int count = 0; //3.1提供一个循环遍历数组寻找要删除数据 for(int i = 0; i<arr.length;i++){ if(arr[i] == num){ //如果if语句成立就证明数组中是存在要删除的数据的 //3.2在提供一个循环使用删除数据位置的后一个数据向前覆盖操作 for(int j = i;j<arr.length-1;j++){ arr[j] = arr[j+1]; } //循环结束之后就证明删除完成,统计计数 count++; } } //真删除【减容】 //在创建一个数组存储删除之后的数据 /* int[] temp = new int[arr.length-count]; for(int i = 0 ; i<arr.length-count;i++){ temp[i] = arr[i]; } //将存储着真删除数据的数据引用赋值给arr arr = temp; temp = null; //删除temp与堆中关联 //在打印arr数组就是真删除,长度也改变了 System.out.println("真删除之后arr数组的长度:"+arr.length);*/ //4.提供打印操作 System.out.print("删除数组中数之后arr数组中元素:["); for(int i = 0 ; i<arr.length-count;i++){ if(i != arr.length-1-count){ System.out.print(arr[i]+","); }else{ System.out.println(arr[i]+"]"); } } System.out.println("删除之后arr数组的长度:"+arr.length); } }
(补充)调试技巧
使用IDEA的调试技巧,帮助开发人员理解程序执行过程,需要两个步骤:
添加断点
单步执行
快捷键:
F7单步进入
Step Into F8单步跳过
Step OverF9继续执行 Resume
查看变量窗口、断点窗口
插入排序和快速排序 (后续扩展补充)