第三阶段-数组高级03
数组拷贝
需求:定义一个方法arraycopy, 从指定源数组中从指定的位置开始复制指定数量的元素到目标数组的指 定位置。
package cn.wolfcode02.arraycpy;
public class ArrayUtils {
private ArrayUtils(){}
public static void arraycopy(int[] arr,int fromIndex,int[] arr2,int toIndex,int length){
for (int i = 0;i < length;i++){
arr2[toIndex + i] = arr[fromIndex + i];
}
}
}
测试类:
package cn.wolfcode02.arraycpy;
import java.util.Arrays;
public class Test01 {
public static void main(String[] args) {
int[] arr = {10,20,30,40,50};
int[] arr2 = new int[10];
ArrayUtils.arraycopy(arr,0,arr2,4,4);
for (int item : arr){
System.out.print(item + " ");
}
System.out.println();
for (int item : arr2){
System.out.print(item + " ");
}
}
}
结果:
10 20 30 40 50
0 0 0 0 10 20 30 40 0 0
排序操作
1.冒泡排序原理
对未排序的各元素从头到尾依次比较相邻的两个元素的大小,如果前一个元素大于后一个元素则交换位置,经过第一轮比较后可以得到最大值,同理第二轮比较后出现第二大值,以此类推。
第1轮比较:需要比较5次,比较完出现第一个大值。
第2轮比较:需要比较4次,比较完出现第二大值。
第3轮比较:需要比较3次,比较完出现第三大值。
...
可以看出如有N个元素,则需要N-1轮比较,第M轮需要N-M次比较
冒泡排序底层代码:
package cn.wolfcode03.sort;
import java.util.Arrays;
public class ArrayUtils {
private ArrayUtils(){
}
public static void bubbleCopy(int[] arr){
int temp;
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 = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
System.out.print(Arrays.toString(arr));
}
}
测试:
public class Test01 {
public static void main(String[] args) {
int[] arr = {3,8,4,2,9,7,8,5,4,3,1};
ArrayUtils.bubbleCopy(arr);
}
}
二分法查找
1.查找数组元素的算法
- 线性查找:从头找到尾,性能比较低
- 二分法查找(折半查找):前提数组元素是有序的,性能非常优异。
2.二分法搜索原理
随机一个有序数组[1,100],猜一个整数a。
- 先从数组中间开始猜,若是提示偏小,则判断该随机数在[51,100]
- 然后就在 (51+100)/2 处猜,若是提示偏大,则判断该随机数在[51,74]
- 那么继续猜 (51+74)/2
- 如此每次都可以排除一半,剩下一半的可能性,直到猜到为止。
二分法查找底层代码:
public class ArrayUtils {
private ArrayUtils(){
}
/**
* 二分查找法
* @param array 目标数组
* @param key 目标元素
* @return 返回索引,如果没有找到返回-1
*/
public static int binarySearch(int[] array,int key){
int low = 0;
int high = array.length-1;
int mid,val;
while (low <= high){
mid = (low + high) / 2;
val = array[mid];
if (val < key){
low = mid + 1;
}else if (val > key){
high = mid - 1;
}else {
return mid;
}
}
// 没找到就返回-1
return -1;
}
}
测试:
public class Test01 {
public static void main(String[] args) {
//用二分法查找数组{1,2,3,4,5,6,7,8,9}中的8
// 查询的元素在数组的右半边
int[] array = {1,2,3,4,5,6,7,8,9};
int idx = ArrayUtils.binarySearch(array, 8);
System.out.println(idx);
// 查询的元素在数组中不存在
int idx2 = ArrayUtils.binarySearch(array, 10);
System.out.println(idx2);
// 查询的元素在数组的左半边
int idx3 = ArrayUtils.binarySearch(array,2);
System.out.println(idx3);
}
}
操作数组的API-Arrays
1.打印数组元素
2.拷贝数组元素
3.数组元素排序
4.数组元素二分查找
import java.util.Arrays;
public class Test01 {
public static void main(String[] args) {
// 遍历数组
// 1> 返回数组的字符串形式,Arrays.toString
int[] arr = {1,5,7,8,2,4,3};
String s = Arrays.toString(arr);
System.out.println(s);
// 复制数组,返回一个一模一样的新数组
// 2> Arrays.copyOf(array,newLength)
int[] arr1 = {1,4,8,9,4,5,2,3};
// 只能从头开始复制
int[] newArr =Arrays.copyOf(arr1,10);
System.out.println(Arrays.toString(newArr));
// 数组复制的底层方法 System.arraycopy(int[] arr,int fromIndex,int[] newArr,int toIndex,int length)
int[] arr2 = {1,4,8,9,4,5,2,3};
int[] newArr2 = new int[10];
System.arraycopy(arr2,3,newArr2,3,5);
System.out.println(Arrays.toString(newArr2));
// 3> Arrays.sort 有序排列
int[] arr3 = {1,4,8,9,4,5,2,3};
Arrays.sort(arr3);
System.out.println(Arrays.toString(arr3));
// 4> Arrays.binarySearch(array,key) 二分法查找
int[] arr4={1,2,3,4,5,6,7,8,9};
int i = Arrays.binarySearch(arr4, 8);
System.out.println(i);
}
}
数组元素的增删改查操作
1.初始化操作
使用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);
}
2.打印输出操作
// 打印输出操作
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();
}
3.追加操作,扩容操作
因为数组的长度是固定的,此时的players数组只能存储5个元素,如果再多存储一个就报错:数组索引 越界。此时就要考虑在保存操作时对数组做扩容操作。
扩容的原理是:
- 创建一个原数组长度两倍长的新数组
- 把旧数组中的所有元素拷贝到新数组中
- 把新数组的引用赋给旧数组变量
// 追加操作
// 向球场上添加一个球员(号码)
public void add(Integer number){
this.players[size] = number;
// 球员个数增加1
size++;
}
// 向球场上添加一个球员(号码)
public void add(Integer number){
// 检测容器容量是否已满,如果已满,需要拓容。
if(size == players.length){
this.players = Arrays.copyOf(this.players, size * 2);
}
// ---------------------------
this.players[size] = number;
// 球员个数增加1
size++;
}
4.查询操作
需求:查询指定索引位置球员的球衣号码是多少,如查询索引位置为2的球衣号码是33。 其实就是返回数组中,指定索引对应的元素值。
// 查询操作
public Integer get(int index) {
if (index < 0 || index >= size) {
System.out.println("索引越界");
return null;
}
return players[index];
}
5.修改操作
需求:替换场上索引位置为2的球员,使用333号替换33号
// 修改操作
//替换指定位置的球员号码
public void set(int index, Integer newPlayerNumber) {
if (index < 0 || index >= size) {
System.out.println("索引越界");
return;
}
this.players[index] = newPlayerNumber;
}
6.删除操作
需求:罚下场上索引位置为2的球员(直接罚下,没有补位)。
删除操作的原理,把后续的元素整体往前挪动一个位置。
// 删除操作
//删除指定位置的球员号码
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--;
}
MyArrayList
import java.util.Arrays;
public class MyArrayList {
// 存储元素容器
private Object[] elementData = null;
// 记录元素个数
private int size = 0;
// 自定义初始容量
public MyArrayList(int initialCapacity) {
if (initialCapacity < 0) {
System.out.println("初始容量不能为负数");
return;
}
this.elementData = new Object[initialCapacity];
}
// 默认初始容量为10
public MyArrayList() {
this(10);
}
// 向容器中添加一个元素
public void add(Object e) {
// 如果容器容量已满,此时需要扩容,此时扩容机制为原来容量的2倍
if (size == elementData.length) {
this.elementData = Arrays.copyOf(this.elementData, size * 2);
}
// -----------------------------------------
this.elementData[size] = e;
size++;// 容器中元素数量加1
}
// 查询指定位置的元素
public Object get(int index) {
if (index < 0 || index >= size) {
System.out.println("索引越界");
return null;
}
return this.elementData[index];
}
// 替换指定索引位置的元素
public void set(int index, Object e) {
if (index < 0 || index >= size) {
System.out.println("索引越界");
return;
}
this.elementData[index] = e;
}
// 删除指定索引位置的元素
public void remove(int index) {
if (index < 0 || index >= size) {
System.out.println("索引越界");
return;
}
for (int i = index; i < size - 1; i++) {
this.elementData[i] = this.elementData[i + 1];
}
this.elementData[size - 1] = null;
size--;
}
public String toString() {
if (elementData == null) {// 如果没有初始化容器
return "null";
}
if (size == 0) {// 如果容器中元素数量为0
return "[]";
}
StringBuilder sb = new StringBuilder(40);
sb.append("[");
for (int index = 0; index < size; index++) {
sb.append(this.elementData[index]);
// 如果不是最后一个元素
if (index != size - 1) {
sb.append(",");
} else {
sb.append("]");
}
}
return sb.toString();
}
}