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 和 count1
        System.out.println("arr1 = " + arr1); // 打印 ArrayList 内容
        System.out.println("count1 = " + count1); // 打印质数的个数
    }
}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值