数组相关算法
数组
数组的声明
数据类型[] 数组名,或数据类型 数组名[].
例:int[] a或int a[].
数组的初始化
动态初始化
数据类型[] 数组名=new 数据类型[数组长度]
例:int[] a=new int[6]
初始化操作:先声明,后赋值。或者声明赋值可同时进行。
赋值格式:数组名[下标]=值。
取值格式:数据类型 变量名=数组名[索引值]
静态初始化
数据类型[] 数组名=new 数据类型[]{数组元素}
例:int[] a=new int[]{1,2,3,4,5,6}
初始化操作:先声明,后赋值。
例:int[] age;age=new int []{数组元素}
声明赋值可同时进行。
例:int[] age=new int[]{数组元素}
静态省略初始化
数据类型[] 数组名={数组元素},
例:int[] a={1,2,3,4,5,6}.
初始化操作:只能声明赋值同时进行。
例:int[] age={数组元素}.
数组的默认值
数组声明后若未进行赋值操作,则数组按照默认值进行操作。
整型数组:默认值为0。
浮点数型数组:默认值为0.0。
布尔型数组:默认值为false。
字符型数组:默认值为不可见字符。
引用数据类型数组:默认值为null。
NullpointerException:空指针异常,指数组取值时索引值超过数组长度时会产生的报错。(注意 null与0的区别:null指没有为数组开辟空间;而0指的是开辟了空间,空间长度为0.
二维数组
指的是数组元素为一维数组的数组
初始化操作:
动态初始化
数据类型[][] 数组名=new 数据类型[数组长度][]
int[][] a=new int[6][].
静态初始化
数据类型[][] 数组名=new 数据类型[][]{数组元素}
例:int[][] a=new int[][]{{1},{2},{3},{4}}.
静态省略初始化
数据类型[][] 数组名={数组元素}
例:int[][] a={{1},{2},{3},{4}}.
多维数组
例:int[] a,b[](a为一维数组,b为二维数组)。
数组的相关算法
(1)元素交换:
以数组a为例,取出a的元素a[x],和a[y]进行交换,若数组为引用数据类型,采用定义中间变量temp的方式,其他的则可使用两数异或的方式快速实现交换。
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] ns = { 5, 2, 6, 7, 8, 3, 1, 9, 4 };
// 排序前
System.out.println("排序前:" + Arrays.toString(ns));
for (int i = 0 ,n = ns.length; i < n - 1; i++) {
for (int k = 0; k < n - 1 - i ; k++) {
if (ns[k] > ns[k+1]) {
// 交换ns[k]和ns[k+1]:
int tmp = ns[k];
ns[k] = ns[k+1];
ns[k+1] = tmp;
}
}
}
// 排序后
System.out.println("排序后:" + Arrays.toString(ns));
}
}
(2)数组正序遍历:
以数组a为例,for(int i=0;i<a.length;i++)
public class Main {
public static void main(String[] args) {
int[] ns = { 1, 4, 9, 16, 25 };
for (int i = 0; i < ns.length; i++) {
int n = ns[i];
System.out.println(n);
}
}
}
(3)数组逆序遍历:
以数组a为例,for(int i=a.length;i>=0;i–)
public class Main {
public static void main(String[] args) {
int[] ns = { 1, 4, 9, 16, 25 };
for (int i = ns.length; i >= 0; i--) {
int n = ns[i];
System.out.println(n);
}
}
}
(4)数组正序遍历前半部分:
以数组a为例,for(int i=0;i<a.length/2;i++)
int[] a = {1, 2, 3, 4, 5, 6, 7, 8};
for (int i = 0; i < a.length / 2; i++) {
System.out.println(a[i]);
}
(5)数组逆序遍历后半部分:
以数组a为例,for(int i=a.length-1;i>=a.length/2;i–)
int[] a = {1, 2, 3, 4, 5, 6, 7, 8};
for (int i = a.length - 1; i >= a.length / 2; i--) {
System.out.println(a[i]);
}
(6)数组元素求和:
以数组a为例,int sum=0;for(int i=0;i<a.length;i++);sum+=i;.
int[] a = {1, 2, 3, 4, 5, 6, 7, 8};
int sum = 0;
for (int i = 0; i < a.length; i++) {
sum += a[i];
}
System.out.println("Sum: " + sum);
(7)元素扩大两倍(或缩小一半):
以数组a为例,for(int i=0;i<a.length;i++);a[i]=a[i]<<1(>>1).
int[] a = {1, 2, 3, 4, 5, 6, 7, 8};
// 扩大两倍
for (int i = 0; i < a.length; i++) {
a[i] = a[i] << 1; // 或 a[i] = a[i] * 2;
}
// 打印数组
System.out.println("Array after doubling:");
for (int i : a) {
System.out.print(i + " ");
}
System.out.println();
// 缩小一半
for (int i = 0; i < a.length; i++) {
a[i] = a[i] >> 1; // 或 a[i] = a[i] / 2;
}
// 打印数组
System.out.println("Array after halving:");
for (int i : a) {
System.out.print(i + " ");
}
(8)首位元素交换:
以数组a为例,for(int i=0;i<a.length/2;i++);int k=a.length-1;a[i]和a[k]使用异或的方法或·定义中间变量的方法进行交换。
int[] a = {1, 2, 3, 4, 5, 6, 7, 8};
int k = a.length - 1;
// 使用异或方法交换
for (int i = 0; i < a.length / 2; i++) {
a[i] = a[i] ^ a[k - i];
a[k - i] = a[i] ^ a[k - i];
a[i] = a[i] ^ a[k - i];
}
// 打印数组
System.out.println("Array after swapping using XOR:");
for (int i : a) {
System.out.print(i + " ");
}
System.out.println();
// 使用中间变量交换
// 重新初始化数组
a = new int[]{1, 2, 3, 4, 5, 6, 7, 8};
for (int i = 0; i < a.length / 2; i++) {
int temp = a[i];
a[i] = a[k - i];
a[k - i] = temp;
}
// 打印数组
System.out.println("Array after swapping using temp variable:");
for (int i : a) {
System.out.print(i + " ");
}
(9)For each遍历数组元素;
以数组a为例,for(int i:a);i为输出的元素,而非下标。注意:此方法无法修改数组元素,也无法控制循环的起始位置。
public class Main {
public static void main(String[] args) {
int[] ns = { 1, 4, 9, 16, 25 };
for (int n : ns) {
System.out.println(n);
}
}
}
(10)冒泡排序:
n个元素比较,采用双重for循环,外层循环 n-1,内层循环n-1-i。
for(int i=0;i<a.length-1;i++){ //比较的轮数
for(int j=0;j<a.length-1-i;j++){ //每轮比较的次数
if(a[j] > a[j+1]){ //进行大小值比较(若要逆序,将>改为<)
a[j] = a[j] ^ a[j+1];
a[j+1] = a[j] ^ a[j+1];
a[j] = a[j] ^ a[j+1];
}
}
}
(11)双指针遍历查找元素:
与单指针不同的是,双指针从两头进行查找,效率相对较高.
核心步骤:以数组a,target(目标值),index(目标值下标)为例:
int Index = -1; // 初始化索引为-1,表示未找到目标值
for (int i = 0, j = a.length - 1; i <= j; i++, j--) {
if (target == a[i]) {
Index = i;
break; // 目标找到则退出判断,直接输出
}
if (target == a[j]) {
Index = j;
break; // 目标找到则退出判断,直接输出
}
}
(12)二分法查找:
核心思想为找中间值,用中间值与目标值进行比较,相对效率最高,但此方法只能用于有序数组。
核心步骤:以数组a,target(目标值),index(目标值下标)为例:
int low = 0; // 数组起始下标
int high = a.length - 1; // 数组结束下标
int target = -1; // 初始化目标值为-1,表示未找到目标值
while (low <= high) {
int mid = (low + high) / 2; // 确定中间值下标
if (a[mid] == target) {
target = mid; // 输出结果
break;
} else if (a[mid] > target) {
high = mid - 1; // 在数组前半部分查找
} else if (a[mid] < target) {
low = mid + 1; // 在数组后半部分查找
}
}
(13)两个数组合并:
以数组a,b,为原数组,c为合并后的数组为例。
方法1:逐个遍历两个数组,将元素存入新数组
public class ArrayMerge {
public static void main(String[] args) {
int[] a = {1, 2, 3, 4};
int[] b = {5, 6, 7, 8};
int[] c = new int[a.length + b.length];
// 将a数组的元素存入c数组
for (int i = 0; i < a.length; i++) {
c[i] = a[i];
}
// 将b数组的元素存入c数组
for (int i = 0; i < b.length; i++) {
c[i + a.length] = b[i];
}
// 打印合并后的数组
System.out.println("Merged array:");
for (int i : c) {
System.out.print(i + " ");
}
}
}
方法2:交替检查两个数组,依次存入新数组
public class ArrayMerge {
public static void main(String[] args) {
int[] a = {1, 2, 3, 4};
int[] b = {5, 6, 7, 8};
int[] c = new int[a.length + b.length];
for (int i = 0; i < a.length || i < b.length; i++) {
if (i < a.length) {
c[i] = a[i];
}
if (i < b.length) {
c[i + a.length] = b[i];
}
}
// 打印合并后的数组
System.out.println("Merged array:");
for (int i : c) {
System.out.print(i + " ");
}
}
}
(14)拉链法合并两个有序数组:
核心思想为两个数组的元素相互比较,按照排序要求依次放入新数组。
核心步骤: 以数组a,b,为原数组,c为合并后的数组为例。
package apesource.knowledge02.数组操作;
import java.util.Arrays;
//拉链法合并两个数组
public class Demo03 {
public static void main(String[] args) {
// 有序的数组--合并后仍然有序
int[] ns1 = { 1, 5, 7, 9 };
int[] ns2 = { 2, 3, 4, 6, 10, 12, 15, 18 };
// 创建新数组
int[] newArr = new int[ns1.length + ns2.length];
// 定义变量
int i = 0, j = 0, k = 0;
// 循环放元素
while (i < ns1.length && j < ns2.length) {
if (ns1[i] < ns2[j]) {
newArr[k++] = ns1[i++];
} else {
newArr[k++] = ns2[j++];
}
}
//数组1中的部分元素没放完
while(i<ns1.length) {
newArr[k++] = ns1[i++];
}
//数组2中的部分元素没放完
while(j<ns2.length) {
newArr[k++] = ns2[j++];
}
// if (i < ns1.length) {
// System.arraycopy(ns1, i, newArr, k, ns1.length - i);
// }
//
// if (j < ns2.length) {
// System.arraycopy(ns2, j, newArr, k, ns2.length - j);
// }
System.out.println(Arrays.toString(newArr));
}
}
(15)数组乱序:
核心思想为产出随机下标与数组元素交换。
import java.util.Arrays;
public class ArrayShuffle {
public static void main(String[] args) {
int[] a = {1, 2, 3, 4, 5, 6, 7, 8};
// 打乱数组
for (int i = a.length - 1; i > 0; i--) {
int random = (int) (Math.random() * i); // 取下标值的随机数
// 交换a[i]和a[random]的值
a[i] = a[i] ^ a[random];
a[random] = a[i] ^ a[random];
a[i] = a[i] ^ a[random];
}
// 打印打乱后的数组
System.out.println("Shuffled array:");
System.out.println(Arrays.toString(a));
}
}
(16)数组旋转:
以数组a右旋w次为例。
方法1:在原数组上进行操作
import java.util.Arrays;
public class ArrayRotate {
public static void main(String[] args) {
int[] a = {1, 2, 3, 4, 5, 6, 7, 8};
int w = 3; // 右旋次数
for (int j = 0; j < w; j++) { // 旋转次数循环
int last = a[a.length - 1]; // 保存最后一个元素
for (int i = a.length - 1; i > 0; i--) { // 逆序遍历数组
a[i] = a[i - 1]; // 将前一个元素赋值给当前元素
}
a[0] = last; // 将保存的最后一个元素赋值给第一个元素
}
// 打印旋转后的数组
System.out.println("Array after rotation (method 1):");
System.out.println(Arrays.toString(a));
}
}
方法2:创建新数组,将原数组的元素赋给旋转后的位置
import java.util.Arrays;
public class ArrayRotate {
public static void main(String[] args) {
int[] a = {1, 2, 3, 4, 5, 6, 7, 8};
int w = 3; // 右旋次数
int[] b = new int[a.length];
for (int i = 0; i < a.length; i++) { // 遍历数组
b[(i + w) % a.length] = a[i]; // 计算新位置并赋值
}
// 打印旋转后的数组
System.out.println("Array after rotation (method 2):");
System.out.println(Arrays.toString(b));
}
}
注意:此方法与方法1的区别,方法1是在原数组上进行操作,而方法2是创建新数组,将原数组的元素的值赋给旋转后元素的值。
数组操作的相关方法:
(1)数组元素打印:
以数组a为例,Arrays.toString(a),注意:如果直接输出数组a,得到的是a所对应的地址,而非数组的元素.
(2)二维数组元素打印:
数组b为例Arrays.deepToString(a).
import java.util.Arrays;
public class ArrayPrint {
public static void main(String[] args) {
int[] a = {1, 2, 3, 4};
int[][] b = {{1, 2}, {3, 4}};
System.out.println("One-dimensional array: " + Arrays.toString(a));
System.out.println("Two-dimensional array: " + Arrays.deepToString(b));
}
}
(3)数组填充数值:
以数组a为例,
《1》Arrays.fill(a,值)表示对数组a全部填充某一个值
《2》Arrays.fill(a,form,to,值)表示对数组a从位置form到to(不包括to)填充某一个值
import java.util.Arrays;
public class ArrayFill {
public static void main(String[] args) {
int[] a = new int[5];
Arrays.fill(a, 7);
System.out.println("Array filled with 7: " + Arrays.toString(a));
int[] b = new int[5];
Arrays.fill(b, 1, 4, 9);
System.out.println("Array partially filled with 9: " + Arrays.toString(b));
}
}
(4)数组排序:
以数组a为例,
《1》Arrays.sort(a)表示对数组a整体正向排序。
《2》Arrays.sort(a,form,to)表示对数组a从位置form到to(不包括to)正向排序。
import java.util.Arrays;
public class ArraySort {
public static void main(String[] args) {
int[] a = {4, 2, 7, 1, 9};
Arrays.sort(a);
System.out.println("Sorted array: " + Arrays.toString(a));
int[] b = {4, 2, 7, 1, 9};
Arrays.sort(b, 1, 4);
System.out.println("Partially sorted array: " + Arrays.toString(b));
}
}
(5)数组查找(仅限于有序数组):
以数组a为例
《1》Arrays.binaryseach(a,target)表示在数组a整体中查找target。注意此方法有返回值,返回值为int型,即target对应数组的下标。
《2》Arrays.binaryseach(a,form,to,tag
Rget)表示对数组a从位置form到to(不包括to)区间内查找,返回值同上。
import java.util.Arrays;
public class ArraySearch {
public static void main(String[] args) {
int[] a = {1, 2, 3, 4, 5};
int target = 3;
int index = Arrays.binarySearch(a, target);
System.out.println("Index of target: " + index);
int[] b = {1, 2, 3, 4, 5};
int indexPartial = Arrays.binarySearch(b, 1, 4, target);
System.out.println("Index of target in partial array: " + indexPartial);
}
}
(6)数组元素复制:以数组a为例
《1》Arrays.copyOf(a,b)表示从数组a中从第一个元素开始复制b个元素到新数组,b为新数组长度。注意此方法返回值为跟原数组数据类型相同的数组,若复制的元素个数超过a数组,则b数组中除了a数组的部分用默认值补齐。
《2》Arrays.copyOfRange(a,form,to)表示在数组a从位置form到to(不包括to)区间内进行复制,返回值为跟原数组数据类型相同的数组。
《3》system.arrayscopy(a,i,b,j,length)表示在数组a中从i的下标位置复制length个元素到数组b中,开始复制的位置为j。
import java.util.Arrays;
public class ArrayCopy {
public static void main(String[] args) {
int[] a = {1, 2, 3, 4, 5};
// 使用 Arrays.copyOf
int[] b = Arrays.copyOf(a, 3);
System.out.println("Copied array using Arrays.copyOf: " + Arrays.toString(b));
// 使用 Arrays.copyOfRange
int[] c = Arrays.copyOfRange(a, 1, 4);
System.out.println("Copied array using Arrays.copyOfRange: " + Arrays.toString(c));
// 使用 System.arraycopy
int[] d = new int[5];
System.arraycopy(a, 1, d, 2, 3);
System.out.println("Copied array using System.arraycopy: " + Arrays.toString(d));
}
}
(7)数组内容比较是否相同:Arrays.equals(a,b)表示数组a和数组b内容比较相同,返回值为boolean型。
import java.util.Arrays;
public class ArrayEquals {
public static void main(String[] args) {
int[] a = {1, 2, 3, 4, 5};
int[] b = {1, 2, 3, 4, 5};
int[] c = {1, 2, 3, 4, 6};
boolean isEqual = Arrays.equals(a, b);
System.out.println("Arrays a and b are equal: " + isEqual);
boolean isNotEqual = Arrays.equals(a, c);
System.out.println("Arrays a and c are equal: " + isNotEqual);
}
}