您的位置:首页 > 科技 > 能源 > chapter05 数组 知识点Note

chapter05 数组 知识点Note

2024/12/23 16:39:28 来源:https://blog.csdn.net/qq_45654741/article/details/141997784  浏览:    关键词:chapter05 数组 知识点Note
一维数组初始化

数组 一维数组 二维数组 多个数据的组合

数组 引用数据类型 数组元素 数组值 可以是基本数据类型 也可以是引用数据类型

一维数组的声明

元素的数据类型[] 一维数组的名称;

public class ArrayTest1 {public static void main(String[] args) {//比如,要存储一个小组的成绩int[] scores;int[] grades;//System.out.println(scores);//未初始化不能使用//比如,要存储一组字母char[] letters;//比如,要存储一组姓名String[] names;//比如,要存储一组价格double[] prices;}
}

数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3,…};

或 数据类型[] 数组名;

数组名 = new 数据类型[]{元素1,元素2,元素3,…};

int[] arr = new int[]{1,2,3,4,5};//正确
//或
int[] arr;
arr = new int[]{1,2,3,4,5};//正确
int[] arr = {1,2,3,4,5}

数组动态初始化

数组变量的初始化和数组元素的赋值操作分开进行,即为动态初始化。

数组存储的元素的数据类型[] 数组名字 = new 数组存储的元素的数据类型[长度];

或 数组存储的数据类型[] 数组名字;

数组名字 = new 数组存储的数据类型[长度];

int[] arr = new int[5];
int[] arr;
arr = new int[5];
// 错误写法
int[] arr = new int[5]{1,2,3,4,5};//错误的,后面有{}指定元素列表,就不需要在[]中指定元素个数了。

数组元素默认初始值

整数型数组元素默认初始化值 0

浮点型数组元素默认初始化值 0.0

字符型数组元素默认初始化值 0

boolean型数组元素默认初始化值 false

引用数据类型数组元素默认初始化值 null

一维数组内存解析

Java内存结构 将内存区域划分为5个区域 程序计数器 虚拟机栈 本地方法栈 堆 方法区

基本数据类型存栈 引用数据类型存堆

数组赋值是浅拷贝

在 Java 中,数组的赋值实际上是进行了浅拷贝(Shallow Copy),而不是深拷贝(Deep Copy)。

当将一个数组变量赋值给另一个数组变量时,实际上是将数组的引用(内存地址)进行了复制。这意味着原始数组和新数组引用同一块内存空间,它们指向相同的对象。

由于数组是引用类型,在进行浅拷贝时,只复制了数组的引用,并没有复制数组中的元素。因此,如果通过一个数组变量修改了数组中的元素,那么另一个数组变量也会反映出这个改变。

int[] array1 = {1, 2, 3};
int[] array2 = array1; // 进行了浅拷贝array2[0] = 10;System.out.println(Arrays.toString(array1)); // 输出 [10, 2, 3]
System.out.println(Arrays.toString(array2)); // 输出 [10, 2, 3]

可以看到,修改 array2 中的元素也会影响到 array1 中的元素,因为它们引用同一个数组对象。

如果要实现数组的深拷贝,即创建一个新的数组并复制原始数组中的元素到新数组中,可以使用 Arrays.copyOf() 方法或手动遍历元素进行复制。

int[] array1 = {1, 2, 3};
int[] array2 = Arrays.copyOf(array1, array1.length); // 进行了深拷贝array2[0] = 10;System.out.println(Arrays.toString(array1)); // 输出 [1, 2, 3]
System.out.println(Arrays.toString(array2)); // 输出 [10, 2, 3]

通过使用 Arrays.copyOf() 方法,我们创建了一个新的数组 array2,并将 array1 中的元素复制到了 array2 中。因此,对 array2 的修改不会影响到 array1

二维数组的声明推荐
// 元素的数据类型[][] 二维数组的名称;
//存储多组成绩
int[][] grades;
//存储多组姓名
String[][] names;
// int[] x, y[];  x为一维数组 y为二维数组  y 是二维整数数组,其中每个元素都是一维整数数组
// 完整写法  int[][] y

二维数组的初始化

int[][] arr = new int[][]{{3,8,2},{2,7},{9,0,1,6}};  //声明与初始化必须在一句完成

二维数组动态初始化

int[][] arr = new int[3][2];  
String[][] arr = new String[3][4];
// 或者 int[][] arr = new int[3][];

多维数组的遍历展示

for(int i=0; i<arr.length; i++){for(int j=0; j<arr[i].length; j++){System.out.print(arr[i][j] + " ");}System.out.println();
}

二维数组本质上是元素类型是一维数组的一维数组

数组之间赋值需维数一样

数组常见算法

均值 总和 最值

数组常见算法 排序优化

特征值计算 数组赋值 复制

public class ArrayCaluate {public static void main(String[] args) {/*** 定义一个int型的一维数组,包含10个元素,分别赋一些随机整数,然后求出所有元素的最大值,最小值,总和,平均值,* 并输出出来。 [10,99]  (int)(Math.random() * (b - a + 1)) + a;*/int[] arr1 = new int[10];for (int i = 0; i < arr1.length; i++) {arr1[i] = (int) (Math.random() * (99 - 10 + 1) + 10);System.out.print(arr1[i] + "\t");}int max = arr1[0];int min = arr1[0];int sum = 0;for (int i = 0; i < arr1.length; i++) {if (max < arr1[i]) {max = arr1[i];}if (min > arr1[i]) {min = arr1[i];}sum += arr1[i];}System.out.println();System.out.println("最大值: " + max);System.out.println("最小值: " + min);double avgValue = sum / arr1.length;System.out.println("总和: " + sum);System.out.println("平均值: " + avgValue);/*** 评委打分** 分析以下需求,并用代码实现:** (1)在编程竞赛中,有10位评委为参赛的选手打分,分数分别为:5,4,6,8,9,0,1,2,7,3** (2)求选手的最后得分(去掉一个最高分和一个最低分后其余8位评委打分的平均值)*/int scores[] = {5, 4, 6, 8, 9, 0, 1, 2, 7, 3};int sum2 = 0;int max2 = scores[0];int min2 = scores[0];for (int i =0; i< scores.length; i++){if(max2 < scores[i]){max2 = scores[i];}if(min2 > scores[i]){min2 = scores[i];}sum2 += scores[i];}System.out.println("选手最终分数 " + (sum2 - max2 - min2) / (scores.length - 2));}
}

数组赋值与复制区别

数组赋值 浅拷贝 (影响原数组)数组复制 深拷贝

//  数组赋值
int[] arr1;
int[] arr2;
arr1 = new int[]{2, 3, 5, 7, 11, 13, 17, 19};
arr2 = arr1;
for (int i = 0; i < arr2.length; i++) {if(i % 2 == 0){arr2[i] = i;}
}
System.out.println(Arrays.toString(arr1));
System.out.println(Arrays.toString(arr2));
// 数组复制
int[] arr1;
int[] arr2;
arr1 = new int[]{2, 3, 5, 7, 11, 13, 17, 19};arr2 = new int[arr1.length];for (int i = 0; i < arr2.length; i++) {arr2[i] = arr1[i];if(i % 2 == 0){arr2[i] = i;}
}
System.out.println(Arrays.toString(arr1));
System.out.println(Arrays.toString(arr2));

数组 反转 扩容 缩容

数组反转

int[] arr = new int[]{34, 54, 3, 2, 65, 7, 34, 5, 76, 34, 67};
for (int i = 0; i < arr.length / 2; i++) {int temp = arr[i];arr[i] = arr[arr.length - i - 1];arr[arr.length - i - 1] = temp;
}
System.out.println(Arrays.toString(arr));

数组扩容

/*** 现有数组 int[] arr = new int[]{1,2,3,4,5};* 现将数组长度扩容1倍,并将10,20,30三个数据添加到arr数组中,如何操作?*/int[] arr = {1, 2, 3, 4, 5};int[] arr2 = new int[arr.length * 2];for (int i = 0; i < arr.length; i++){arr2[i] = arr[i];
}arr2[arr.length] = 10;
arr2[arr.length + 1] = 20;
arr2[arr.length + 2] = 30;arr = arr2;System.out.println(Arrays.toString(arr));

数组缩容

/*** int[] arr3={1,2,3,4,5,6,7}。现需删除数组中索引为4的元素*/
int[] arr3={1,2,3,4,5,6,7};
int deleteIndex = 4;
for (int i = deleteIndex; i< arr3.length - 1;i++){arr3[i] = arr3[i+1];
}
arr3[arr3.length-1] = 0;
System.out.println(Arrays.toString(arr3));
int[] arr3={1,2,3,4,5,6,7};
int deleteIndex = 4;
int[] arr4 = new int[arr3.length -1];for (int i = 0; i< deleteIndex; i++){arr4[i] = arr3[i];
}for (int i = deleteIndex; i< arr3.length - 1; i++){arr4[i] = arr3[i+1];
}
System.out.println(Arrays.toString(arr4));
数组查找 冒泡排序 快速排序

线性查找 算法简单 效率低 复杂度 O(n)

/*** 线性查找* int[] arr1 = new int[]{34,54,3,2,65,7,34,5,76,34,67};* 查找元素5是否在上述数组中出现过?如果出现,输出对应的索引值*/int[] arr1 = new int[]{34, 54, 3, 2, 65, 7, 34, 5, 76, 34, 67};
for (int i = 0; i < arr1.length; i++) {if (arr1[i] == 5) {System.out.println("对应5的索引值是" + i);break;}
}if(i == arr1.length){System.out.println("没找到")
}

二分法查找 效率高 复杂度 O(log2N) 数组必须有序

二分法查找需数组有序

/*** 二分法查找** 定义数组:int[] arr2 = new int[]{2,4,5,8,12,15,19,26,37,49,51,66,89,100};* 查找元素5是否在上述数组中出现过?如果出现,输出对应的索引值。* 要求:使用二分法查找,时间复杂度为O(log2^N)*/
int[] arr2 = new int[]{2, 4, 5, 8, 12, 15, 19, 26, 37, 49, 51, 66, 89, 100};int target = 5;int head = 0; // 默认首索引
int end = arr2.length - 1; // 默认尾索引boolean isFlag2 = false;while (head <= end) {// 计算中间索引int middle = (head + end) / 2;if (target == arr2[middle]) {System.out.println("找到元素5,对应的索引值是" + middle);isFlag2 = true;break;} else if (target < arr2[middle]) {end = middle - 1;} else if (target > arr2[middle]) {head = middle + 1;}
}if(!isFlag2){System.out.println("未找到");
}

冒泡排序 O(n^2) 稳定 简单

时间复杂度 空间复杂度 稳定性

相邻两个元素比较 比较

bubbleSort

排序目的快速查找

/*** 使用冒泡排序,实现整型数组元素的排序操作* 比如:int[] arr = new int[]{34,54,3,2,65,7,34,5,76,34,67};*/int[] arr = new int[]{34, 54, 3, 2, 65, 7, 34, 5, 76, 34, 67};
long start = System.currentTimeMillis();
for (int j = 0; j < arr.length - 1; j++) {//    执行一轮 找出最大的数for (int i = 0; i < arr.length - 1 - j; i++) {if (arr[i] > arr[i + 1]) {//交换int temp = arr[i];arr[i] = arr[i + 1];arr[i + 1] = temp;}}
}
long end = System.currentTimeMillis();
System.out.println("执行时间:" + (end - start) + "ms");
System.out.println(Arrays.toString(arr));

快速排序 O(nlog2N) 快 递归思想

/*** 快速排序* 通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分关键字小,* 则分别对这两部分继续进行排序,直到整个序列有序。** @author 尚硅谷-宋红康* @create 13:18**/
public class QuickSort {public static void main(String[] args) {int[] data = {9, -16, 30, 23, -30, -49, 25, 21, 30};System.out.println("排序之前:");for (int i = 0; i < data.length; i++) {System.out.print(data[i]+" ");}quickSort(data);//调用实现快排的方法System.out.println("\n排序之后:");for (int i = 0; i < data.length; i++) {System.out.print(data[i]+" ");}}public static void quickSort(int[] data) {subSort(data, 0, data.length - 1);}private static void subSort(int[] data, int start, int end) {if (start < end) {int base = data[start];int low = start;int high = end + 1;while (true) {while (low < end && data[++low] - base <= 0);while (high > start && data[--high] - base >= 0);if (low < high) {//交换data数组[low]与[high]位置的元素swap(data, low, high);} else {break;}}//交换data数组[start]与[high]位置的元素swap(data, start, high);//经过代码[start, high)部分的元素 比[high, end]都小//通过递归调用,对data数组[start, high-1]部分的元素重复刚才的过程subSort(data, start, high - 1);//通过递归调用,对data数组[high+1,end]部分的元素重复刚才的过程subSort(data, high + 1, end);}}private static void swap(int[] data, int i, int j) {int temp = data[i];data[i] = data[j];data[j] = temp;}
}
Arrays工具类的使用

java.util.Arrays类即为操作数组的工具类,包含了用来操作数组(比如排序和搜索)的各种方法。 比如:

  • 数组元素拼接

    • static String toString(int[] a) :字符串表示形式由数组的元素列表组成,括在方括号(“[]”)中。相邻元素用字符 ", "(逗号加空格)分隔。形式为:[元素1,元素2,元素3。。。]

    • static String toString(Object[] a) :字符串表示形式由数组的元素列表组成,括在方括号(“[]”)中。相邻元素用字符 ", "(逗号加空格)分隔。元素将自动调用自己从Object继承的toString方法将对象转为字符串进行拼接,如果没有重写,则返回类型@hash值,如果重写则按重写返回的字符串进行拼接。

    • Arrays.toString(arr)

  • 数组排序

    • static void sort(int[] a) :将a数组按照从小到大进行排序 Arrays.sort(a)
    • static void sort(int[] a, int fromIndex, int toIndex) : 将a数组的[fromIndex, toIndex)部分按照升序排列 Arrays.sort(a, fromIndex, toIndex);
    • static void sort(Object[] a) :根据元素的自然顺序对指定对象数组a按升序进行排序。 Arrays.sort(a) 将对象数组a按倒序进行排列 // 使用自定义的比较器进行降序排序 Arrays.sort(a, Comparator.reverseOrder());
    • static void sort(T[] a, Comparator<? super T> c) :根据指定比较器产生的顺序对指定对象数组进行排序。 // 使用自定义的比较器进行排序 Arrays.sort(a, new CustomComparator());
  • 数组元素的二分查找

    • static int binarySearch(int[] a, int key) 、static int binarySearch(Object[] a, Object key) :要求数组有序,在数组中查找key是否存在,如果存在返回第一次找到的下标,不存在返回负数。
  • 数组的复制

    • static int[] copyOf(int[] original, int newLength) :根据original原数组复制一个长度为newLength的新数组,并返回新数组
    • static T[] copyOf(T[] original,int newLength):根据original原数组复制一个长度为newLength的新数组,并返回新数组
    • static int[] copyOfRange(int[] original, int from, int to) :复制original原数组的[from,to)构成新数组,并返回新数组
    • static T[] copyOfRange(T[] original,int from,int to):复制original原数组的[from,to)构成新数组,并返回新数组
  • 比较两个数组是否相等

    • static boolean equals(int[] a1, int[] a2) :比较两个数组的长度、元素 顺序是否完全相同

    • static boolean equals(Object[] a,Object[] a2):比较两个数组的长度、元素是否完全相同

      boolean isEquals = Arrays.equals(arr1,arr2);
      
  • 填充数组

    • static void fill(int[] a, int val) :用val值填充整个a数组

      Arrays.fill(arr, 10)  // arr里的元素都替换成10
      
    • static void fill(Object[] a,Object val):用val对象填充整个a数组

    • static void fill(int[] a, int fromIndex, int toIndex, int val):将a数组[fromIndex,toIndex)部分填充为val值

    • static void fill(Object[] a, int fromIndex, int toIndex, Object val) :将a数组[fromIndex,toIndex)部分填充为val对象*2 位运算 << 1

数组常见异常

角标越界异常

访问数组元素 下标超出 [0,数组名.length-1] 范围时就会报越界异常 ArrayIndexOutOfBoundsException。

空指针异常

数组还未分配存储元素的空间 此时访问元素 会报空指针异常 NullPointerException

如何避免空指针异常?

在后端开发中,也有一些类似的方法可以避免空指针异常。以下是一些常用的做法:

  1. 使用条件判断:在使用对象之前,通过条件判断(如if语句)来检查对象是否为空。例如,在Java中,可以使用类似于if (obj != null)的语句进行检查。
  2. 使用Optional类型:一些编程语言(如Java 8及以上版本)提供了Optional类型,它可以用于封装可能为空的对象,并提供了一系列的操作方法来安全地处理可能为空的情况。使用Optional类型可以避免直接操作空对象引发的空指针异常。
  3. 合理设计数据结构:在后端开发中,同样需要合理设计数据结构,确保对象在需要时已经被正确初始化,不会出现空指针异常。同时,在使用对象之前,进行必要的校验和处理,确保数据的完整性和有效性。
  4. 异常处理:在后端代码中,适当地使用异常处理机制来捕获可能导致空指针异常的情况,从而避免程序意外中断。可以使用try-catch语句来捕获异常,并对异常进行相应的处理。
  5. 日志记录:在后端开发中,合理使用日志记录工具,及时记录可能出现的异常情况,并对异常进行适当的处理和跟踪,以便排查和修复问题。

通过以上方法和编程实践,后端开发人员可以有效地避免空指针异常,并确保代码的稳定性和可靠性。

动态数组
import java.util.ArrayList;
public class PrimeNumbers {public static void main(String[] args) {ArrayList<Integer> arr1 = new ArrayList<>(); // 使用 ArrayList 存储质数int count1 = 0; // 计数质数的变量for (int i = 2; i <= 10000; i++) {boolean isPrime = true;for (int j = 2; j < i; j++) {if (i % j == 0) {isPrime = false;break; // 如果能被整除,不是质数,跳出内循环}}if (isPrime) {arr1.add(i); // 将质数添加到 ArrayList 中count1++;}}// 打印 arr1 和 count1System.out.println("arr1 = " + arr1); // 打印 ArrayList 内容System.out.println("count1 = " + count1); // 打印质数的个数}
}

如果数组 arr1 的大小不确定(即不知道质数的具体个数),可以使用动态数组 ArrayList 来存储质数。ArrayList 在 Java 中可以动态增长,因此可以根据需要添加元素而不需要预先指定大小。之后再说

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com