数组拷贝
(1)定义一个方法arraycopy, 从指定源数组中从指定的位置开始复制指定数量的元素到目标数组的指定位置。
拷贝前:
编辑
拷贝后:
编辑
代码如下:
public class ArrayUtils { private ArrayUtils() { /** * 复制数组操作 * * @param src 源数组 * @param srcPos 源数组中的开始索引位置 * @param dest 目标数组 * @param destPos 目标数据中的开始索引位置 * @param length 要复制的数组长度 */ public static void arraycopy(int[] src, int srcPos, int[] dest, int destPos, int length) { for (int index = 0; index < length; index++) { dest[destPos + index] = src[srcPos + index]; } } }
测试类:
public class Test01ArrayCopy { public static void main(String[] args) { int[] a = new int[]{10, 20, 30, 40, 50, 60, 70}; int[] b = new int[10]; ArrayUtils.arraycopy(a, 2, b, 4, 3); // 测试复制数组后的结果 for (int i = 0; i < b.length; i++) { System.out.print(b[i] + ","); } } }
控制台输出:
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0] [0, 0, 0, 0, 30, 40, 50, 0, 0, 0]
排序操作
(1)完成对int[] arr = new int[]{2,9,6,7,4,1}数组元素的升序排序操作.
编辑
冒泡排序原理
对未排序的各元素从头到尾依次比较相邻两个元素的大小关系,如果前一个元素大于后一个元素则交换位置,经过第一轮比较后可以得到最大值,同理第二轮比较后出现第二大值等。
针对int[] arr = new int[]{ 2, 9, 6, 7, 4, 1 }数组元素做排序操作:
该数组有6个元素,只需要5轮比较。
第1轮比较:需要比较5次,比较完出现第一个大值。 第2轮比较:需要比较4次,比较完出现第二大值。 第3轮比较:需要比较3次,比较完出现第三大值。 ... 可以看出如有N个元素,则需要N-1轮比较,第M轮需要N-M次比较。
交换数组中两个元素的方法
public class ArrayUtils { private ArrayUtils() { } // 通过索引交换数组索引处值 public static void swap(int[] arr, int index1, int index2) { int temp = arr[index1]; arr[index1] = arr[index2]; arr[index2] = temp; } }
排序代码:
public class ArrayUtils { private ArrayUtils() { } public static void swap(int[] arr, int index1, int index2) { int temp = arr[index1]; arr[index1] = arr[index2]; arr[index2] = temp; } public static void bubbleSort(int[] arr) { //第一轮: for (int i = 1; i <= arr.length-1; i++) { if (arr[i - 1] > arr[i]) { swap(arr, i - 1, i); } } //第二轮: for (int i = 1; i <= arr.length - 2; i++) { if (arr[i - 1] > arr[i]) { swap(arr, i - 1, i); } } //第三轮: for (int i = 1; i <= arr.length - 3; i++) { if (arr[i - 1] > arr[i]) { swap(arr, i - 1, i); } } // 第四轮呢? } }
寻找规律,优化上述代码:
public static void bubbleSort(int[] arr) { for (int times = 1; times <= arr.length - 1; times++) { //times表示第几轮比较,值为:1,2,3,4,5 for (int i = 1; i <= arr.length - times; i++) { if (arr[i - 1] > arr[i]) { ArrayUtils.swap(arr, i - 1, i); } } } }
测试:
public class Test02ArraySort { public static void main(String[] args) { int[] arr = new int[] { 2, 9, 6, 7, 4, 1 }; ArrayUtils.bubbleSort(arr); // 测试复制数组后的结果 for (int i = 0; i < arr.length; i++) { System.out.print(arr[i] + ","); } } }
二分法查找
查找数组元素的算法:
线性查找:从头找到尾,性能比较低。
二分法查找(折半查找):前提数组元素是有序的,性能非常优异。
二分法搜索原理
猜数字游戏:
电脑随机生成一个[ 1 , 100 ]之间的整数a,等玩家来猜,猜之后,电脑提示出三种结果:你猜的数偏大,偏小和猜中了。此时为了使用最少次数猜中,玩家必定先猜(1+100)/2的商50,如果此时电脑提示猜的偏小了,那就能推断出该随机数在[ 51 , 100 ]之间,此时再猜(51+100)/2的商75,如果电脑提示猜大了,那么该随机数必在[ 51 , 74 ]之间,那么继续猜(51+74)/2的商,如此每次都可以排除剩下结果一半的可能性,直到猜到为止。
编辑
代码如下:
public class ArrayUtils { private ArrayUtils() { } public static int binarySearch(int[] arr, int key) { int low = 0; int high = arr.length - 1; while (low <= high) { int mid = (low + high) / 2; int midVal = arr[mid]; if (midVal < key) { low = mid + 1; } else if (midVal > key) { high = mid - 1; } else { return mid; } } // 没有找到 return -1; } }
测试类:
public class Test03ArraySearch { public static void main(String[] args) { int[] arr = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9}; int idx = ArrayUtils.binarySearch(arr,8); System.out.println("idx = " + idx); } }
操作数组的API-Arrays
类似打印数组元素的这样的工具性的方法,其实SUN公司的攻城狮们早就写好代码了,并封装在了很多工具类中,我们把这种预先定义好的方法,称为API。对于我们而言,最基本的要求就是能调用这 些方法,当然我们对自己有更高的要求,应该知其然,并知其所以然。
Arrays工具类中的方法,一般都是使用static修饰的。
打开JDK帮助文档,搜索Arrays类,进入该类的文档页面,去找toString方法,发现在Arrays类中有多个
toString方法,他们之间属于重载关系,分别用于打印不同类型的数组。
编辑
如: 查看Arrays类中将int类型数组转换成字符串的toString方法。
编辑
如果看方法列表看不懂怎么使用,使用鼠标左键点击该方法名称,进入该方法的详细:
编辑
打印数组元素
API中还有一个专门操作数组的工具类Arrays,该类提供了对数组元素的拷贝、元素搜索、元素排序、打印等功能方法,且该类为不同数据类型的数组都重载了相同功能的方法。
(1)通过调用Arrays类中的toString方法完成打印数组元素的功能。
public class Test01ToString { public static void main(String[] args) { int[] arr = new int[] { 10, 20, 30, 40, 50, 60, 70 }; String str = Arrays.toString(arr); System.out.println(str); } }
拷贝数组元素
Arrays 中提供了数组复制的方法,copyOf(int[] original, int newLength) 复制指定的数组,截取或者用0填充。
System类中提供了数组元素拷贝的方法,并且支持任意类型的数组拷贝,而不仅仅是int类型数组。
public class Test02ArrayCopy { public static void main(String[] args) { // copyOf // 截取场景 int[] arr = new int[] { 10, 20, 30, 40, 50, 60, 70 }; // int[] newArr = Arrays.copyOf(arr, 3); // 填充场景 int[] newArr = Arrays.copyOf(arr, 10); System.out.println(Arrays.toString(newArr)); // System.arraycopy() int[] arr2 = {1,2,3,4}; int[] newArr2 = new int[10]; System.arraycopy(arr2,0,newArr2,0,arr2.length); System.out.println(Arrays.toString(newArr2)); } }
数组元素排序
Arrays类中已经提供了数组排序的方法sort,并且是调优之后的,性能非常优异,在开发中只需要我们直接调用该方法即可即可。
public class Test03Sort{ public static void main(String[] args) { int[] arr = new int[] { 2, 9, 6, 7, 4, 1 }; System.out.println(Arrays.toString(arr));//排序前Arrays.sort(arr); System.out.println(Arrays.toString(arr));//排序后 } }
数组元素二分查找
Arrays类中已经提供了数组元素的二分查找。
public class Test04Search{ public static void main(String[] args) { int[] arr = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int index = Arrays.binarySearch(arr, 8); System.out.println(index); } }
数组元素的增删改查操作
假设我现在是某个篮球队的教练,需要安排5个球员上场打球。此时需要模拟上场球员的存储,简 单一点,我们就只存储上场球员的球衣号码。那么此时我需要以下几个操作:
(1)初始一个容量为5的容器,用来存储场上的5个球衣号码。
(2)安排5个球员上场,比如球员号码分别为11、22、33、44、55。
(3) 查询指定索引位置球员的球衣号码是多少,如查询索引位置为2的球衣号码是33。
(4)替换场上索引位置为2的球员,使用333号替换33号。
(5)罚下场上索引位置为2的球员(直接罚下,没有补位)。
(6) 打印**出场上球员的球衣号码,打印风格如 [11,22,33,44,55]。
初始化操作
使用Integer数组来存储场上球员号码,提供了两个构造器,一个用于自定义初始化容量,一个用于使用默认的初始化容量10。
public class PlayerList { // 存储场上球员的号码 private Integer[] players = null; // 记录场上球员的数量 private int size = 0; public PlayerList(int capacity){ if(capacity < 0){ System.out.println("初始容量不能为负数"); return; } this.players = new Integer[capacity]; } public PlayerList() { this(0); } }
测试类:
public class Test01PlayerList { public static void main(String[] args) { //初始容量为默认的10 PlayerList list1 = new PlayerList(); //自定义初始化容量为5 PlayerList list2 = new PlayerList(5); //自定义初始化容量为20 PlayerList list3 = new PlayerList(20); } }
打印输出操作
public String toString() { if(null == players){ return "null"; } if(0 == size){ return "[]"; } StringBuilder sb = new StringBuilder(); sb.append("["); for(int index = 0;index < size;index++){ sb.append(this.players[index]); if(index != size - 1){ sb.append(","); }else{ sb.append("]"); } } return sb.toString(); }
追加操作
// 向球场上添加一个球员(号码) public void add(Integer number){ this.players[size] = number; // 球员个数增加1 size++; }
测试类:
public class Test01PlayerList { public static void main(String[] args) { //初始化容器,设置初始化容量为5 PlayerList list = new PlayerList(5); System.out.println(list); //向容器中添加5个元素(球员号码) list.add(11); list.add(22); list.add(33); list.add(44); list.add(55); //打印容器中每一个元素 ystem.out.println(list); } }
因为数组的长度是固定的,此时的players数组只能存储5个元素,如果再多存储一个就报错:数组索引越界。此时就要考虑在保存操作时对数组做扩容操作。
扩容的原理是:
创建一个原数组长度两倍长的新数组
把旧数组中的所有元素拷贝到新数组中
把新数组的引用赋给旧数组变量
保存操作时扩容操作:
// 向球场上添加一个球员(号码) public void add(Integer number){ // 检测容器容量是否已满,如果已满,需要拓容。 if(size == players.length){ this.players = Arrays.copyOf(this.players, size * 2); } // --------------------------- this.players[size] = number; // 球员个数增加1 size++; }
查询操作
(1)查询指定索引位置球员的球衣号码是多少,如查询索引位置为的球衣号码是。其实就是返回数组中,指定索引对应的元素值。
public Integer get(int index) { if (index < 0 || index >= size) { System.out.println("索引越界"); return null; } return players[index]; }
测试类:
public class Test01PlayerList { public static void main(String[] args) { Integer r = list.get(2); System.out.println(r); } }
修改操作
(1)替换场上索引位置为2的球员,使用333号替换33号
//替换指定位置的球员号码 public void set(int index, Integer newPlayerNumber) { if (index < 0 || index >= size) { System.out.println("索引越界"); return; } this.players[index] = newPlayerNumber; }
删除操作
(1)罚下场上索引位置为的球员(直接罚下,没有补位)。删除操作的原理,把后续的元素整体往前挪动一个位置。
//删除指定位置的球员号码 public void remove(int index) { if (index < 0 || index >= size) { System.out.println("索引越界"); return; } for (int i = index; i < size - 1; i++) { players[i] = players[i + 1]; } players[size - 1] = null; size--; }
测试类:
public class Test01PlayerList { public static void main(String[] args) { PlayerList list = new PlayerList(5); list.add(11); list.add(22); list.add(33); list.add(44); list.add(55); list.remove(2); System.out.println(list); } }
以上就是Java入门第七天的全部内容了。
资料文档地址:Java开发零基础篇:day07数组高级.pdf