Java基础5

数组的概念

数组(Array)是多个相同类型数据按照一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理。

 几个相关概念: ①数组名  ②数组的元素  ③数组的下标  ④数组的长度

特点:

  • 数组中的元素在内存中是依次紧密排列的,有序的。
  • 数组,属于引用数据类型的变量。数组的元素,既可以是基本数据类型,也可以是引用数据类型。
  • 数组一旦初始化完成,其长度就确定了并且长度不可更改
  • 创建数组对象会在内存中开辟一块完整的连续空间,占据的空间的大小,取决于数组的长度和数组中元素的类型。

数组的分类:

  • 按照元素的分类:基本数据类型元素的数组;引用数据类型元素的数组
  • 按照数组的维数来分:一维数组、二维数组......

一维数组

初始化:  静态初始化      动态初始化

复制代码
//方式一  静态初始化:数组变量的赋值和数组元素的赋值操作同时进行
        double[] prices;
        prices = new double[]{23.45,35.73,31.74};

        //方式二  动态初始化:数组变量的赋值和数组元素的赋值操作分开进行
        String[] week = new String[7];
        
        //其他的正确方式
        int arr[] = new int[3];
        int[] arr1 = {1,3,6,7}; //类型推断 
复制代码

数组的调用:  角标的范围从0开始,到数组的长度-1结束

为什么数组的编号从0开始?  数组的索引,表示了数组元素距离首地址的偏移量。因为第1个元素的地址与首地址相同,所以偏移量是0.

数组的长度:用来描述数组容器中容量的大小  XXX.length

注意: 数组没有length()方法,有的是length属性;  但是String有length()方法。

复制代码
//初始化
        double[] prices;
        prices = new double[]{23.45,35.73,31.74};
        //数组长度
        System.out.println(prices.length);
        //遍历数组:
        for (int i = 0; i <= prices.length; i++){
            System.out.println(prices[i]);
        }
复制代码

 默认初始化值:

①整数型数组:0  ②浮点型数组:0.0  ③字符型数组:0或者'\u000'(注意不是'0')  ④布尔型数组:false  ⑤引用型数组:null

一维数组的内存分析

Java中的内存区域划分为5个部分:程序计数器、虚拟机栈、本地方法栈、堆、方法区

 > 与目前数组相关的内存结构:  比如: int [ ] arr = new int [ ]{1,2,3};

            >虚拟机栈: 用于存放方法中声明的变量。比如:arr

       >堆: 用于存放数组的实体 (即数组中的所有元素) 比如:1,2,3

举例说明:

 二维数组

二维数组的理解: 可以看做是一维数组array1又作为另一个一维数组array2的元素而存在。其实,从数组底层的运行机制来看,其实没有多维数组。

  • 二维数组的初始化
复制代码
//二维数组静态初始化:
int[][] arr1 = new int[][] {{1,2,3},{4,5},{6,7,8}};
//二维数组动态初始化1:
String[][] arr2 = new String[3][4];
//二维数组动态初始化2:
double[][] arr3 = new double[2][];
//其他初始化:
int arr4[][] = new int[][]{{1,2,3},{4,6},{8,3}};
int [] arr5[] = new int [][]{{2,5},{3,7}};
int arr6[][] = {{2,3},{5,3,7},{3,6}};  //类型推断
String arr7[][] = new String[3][7];
复制代码
  • 二维数组元素的默认初始化值

动态初始化方式1(比如:int[][] arr1 = new int[3][4])

1)  外层元素,默认初始化地址值。

2)  内层元素,默认与一维数组元素的不同类型的默认值规定相同。

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

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

     > 字符型数组元素的默认初始化值:0 (或理解为 '\u0000')

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

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

动态初始化方式2 (比如:int[][] arr = new int[3][])

1) 外层元素,默认存储null

2) 内存元素,不存在。如果调用会报错(NullPointerException)

复制代码
       //二维数组动态初始化1:
        int[][] arr1 = new int[3][2];
        //外层元素默认值:
        System.out.println(arr1[0]);  //[I@776bec8f
        System.out.println(arr1[1]);  //[I@4eec7777
        //内层元素默认值:
        System.out.println(arr1[0][0]);  //0
        boolean[][] arr2 = new boolean[3][4];
        //外层元素默认地址:
        System.out.println(arr2[0]);  //地址值
        //内层元素默认值:
        System.out.println(arr2[0][1]);  //false
        
        //二维数组动态初始化2:
        int[][] arr3 = new int[4][];
        //外层元素默认值:
        System.out.println(arr3[0]);  //null  因为分配了四个空间,是引用类型,但是没有指向,所以默认null
        //内层元素默认值:
        System.out.println(arr3[0][0]);  //报错                        
复制代码

 

  • 二维数组的调用
     //二维数组静态初始化:
        int[][] arr1 = new int[][] {{1,2,3},{4,5},{6,7,8}};
        //调用内层元素
        System.out.println(arr1[0][0]);  //1
        System.out.println(arr1[2][1]);  //7
        //调用外层
        System.out.println(arr1[0]);  //[I@776ec8df  这里会输出地址而不是{1,2,3}
  • 二维数组的长度和遍历
复制代码
     //二维数组静态初始化:
        int[][] arr1 = new int[][] {{1,2,3},{4,5},{6,7,8}};
        //数组的长度
        System.out.println(arr1.length); //3
        System.out.println(arr1[0].length); //3
        System.out.println(arr1[1].length); //2
        //遍历
        for (int i = 0; i < arr1.length; i++){
            for (int j = 0; j < arr1[i].length; j++){
                System.out.print(arr1[i][j]);
            }
            System.out.println();
        }
复制代码

 二维数组的内存解析

 注意:arr2[2][2] = 1; 因为还没开辟空间所以找arr2[2][2]根本找不到,会报错NullPointerException

 二维数组的赋值问题

复制代码
int[] arr1 = new int[10];
byte[] arr2 = new byte[20];
// arr1 = arr2;  编译不通过! 原因:int[]、byte[]是两种不同类型的引用变量

int[][] arr3 = new int[3][2];
// arr3 = arr1;  编译不同。 维度都不相同

arr3[0] = arr1;  //编译正确!
System.out.println(arr3[0]);   //[I@776ec8df
System.out.println(arr1);      //[I@776ec8df
System.out.println(arr3);      //[[I@3b07d329
复制代码

数组的算法

  • 基本算法

复制代码
        //动态初始化创建数组
        int[] arr = new int[10];
        //通过循环给数组赋值:  赋值为两位数[10-99]
        for (int i = 0; i < arr.length; i++){
            arr[i] = int(Math.random()*90)+10;
        }
        
        //求最大值:
        int max = arr[0];
        for (int i = 1; i < arr.length; i++){
            if (arr[i] > max){
                max = arr[i];
            }
        }
        System.out.println("最大值是:" + max);
        
        //求最小值:
        int min = arr[0];
        for (int i = 1; i < arr.length; i++){
            if (arr[i] < max){
                min = arr[i];
            }
        }
        System.out.println("最大值是:" + min);
        
        //求总和:
        int sum = 0;
        for (int i = 0; i < arr.length; i++){
            sum += arr[i];
        }
        System.out.println("总和是:" + sum);
        
        //求平均值:
        int avg = sum/arr.length;
        System.out.println("平均值是:" + avg);                    
复制代码

问题: 对于一个长度6的int型数组,随机赋值1-30,但是数组中不能有重复的数  [注意!]

复制代码
        //动态初始化创建数组
        int[] arr = new int[6];
        for (int i = 0; i < arr.length; i++){
            arr[i] = (int)(Math.random()*30)+1;
            boolean flag = true;
            for (int j = 0; j < i; j ++){
                if (arr[i] == arr[j]){
                    i--;
                    break;
                }
            }
                System.out.println(arr[i]);
        }            
复制代码
  •  回形数

复制代码
import java.util.Scanner;
public class RectangleTest{
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        System.out.println("请输入一个数字:");
        int num = scan.nextInt();
        int arr[][] = new int[num][num];
        int turn = num/2;
        int length = arr[0].length;
        int sum = 1;
        for (int i = 0; i < turn; i++){
            for (int j = 0; j < 4; j++){
                for(int k = 0; k < length-2*i-1; k++){
                    switch (j){
                        case 0:
                            arr[i][i+k] = sum;
                            sum += 1;
                            continue;
                        case 1:
                            arr[i+k][length-i-1] = sum;
                            sum += 1;
                            continue;
                        case 2:
                            arr[length-i-1][length-k-1-i] = sum;
                            sum += 1;
                            continue;
                        case 3:
                            arr[length-k-1-i][i] = sum;
                            sum += 1;
                    }
                }
            }
        }
        if(num%2 == 1){
            arr[turn][turn] = sum;
        }
        for (int i = 0; i < length; i ++){
            for (int j = 0 ; j < length; j ++){
                System.out.print(arr[i][j]+"\t");
            }
            System.out.println();
        }
    }
}
复制代码

其他优秀方法:

复制代码
public class HelloWorld {
    public static void main(String []args) {
       //动态初始化创建数组
        Scanner scan = new Scanner(System.in);
        System.out.println("请输入一个数字:");
        int n = scan.nextInt();
        int[][] arr = new int [n][n];
        
        int count = 0; //要显示的数据
        int maxX = n-1; // x轴的最大下标
        int maxY = n-1; // y轴的最大下标
        int minX = 0;  //x轴最小下标
        int minY = 0;  //y轴最小下标
        while(minX <= maxX){
            for (int x = minX; x <= maxX; x++){
                arr[minY][x] = ++ count;
            }
            minY++;
            for (int y = minY; y <= maxY; y++){
                arr[y][maxX] = ++ count;
            }
            maxX--;
            for(int x = maxX; x >= minX; x--){
                arr[minY][x] = ++count;
            }
            maxY--;
            for(int y = maxY; y >= minY; y--){
                arr[y][minX] = ++count;
            }
            minX++;
        }
        
        for (int i = 0; i < arr.length; i ++){
            for (int j = 0 ; j < arr.length; j ++){
                String space = (arr[i][j] + "").length()==1 ? "0" : "";
                System.out.println(space + arr[i][j]);
            }
            System.out.println();
        }
    }
}
复制代码
  • 数组的值复制

注意:不可以写arr2 = arr1;  //这样得到的是arr1的地址,改动arr2,arr1里面的值一起在变化。

复制代码
        int[] arr1,arr2;
        arr1 = new int[]{1,2,3,4,5,6};
        //复制arr1的数组给arr2
        arr2 = new int[arr1.length];
        for (int i = 0; i < arr2.length; i++){
            if (i%2 == 0){
                arrw[i]=i;
            }
        }            
复制代码
  • 数组的反转

复制代码
     int[] arr1 = new int[]{34,65,3,56,58,24,98,78,45};
        //反转方式1
        for (int i = 0; i < arr.length/2; i++){
            //交互arr[i] 与 arr[arr.length-1-i]的位置的元素
            int temp = arr[i];
            arr[i] = arr[arr.length-1-i];
            arr[arr.length-1-i] = temp;
        }
        
        //反转方式2
        for(int i = 0, j = arr.length-1; i < j; i++, j--){
            //交互arr[i] 与 arr[j]位置的元素
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
        
        //反转方式3  不推荐
        int[] newArr = new int[arr.length];
        for(int i = arr.length-1; i >= 0; i--){
            newArr[arr.length-1-i] = arr[i];
        }
复制代码
  • 数组的扩容与缩容

复制代码
     int[] arr = new int[]{1,2,3,4,5};
        
        //扩容1倍的容量
        int[] newArr = new int[arr.length * 2];
        //将原有数组中的元素复制到新的数组中:
        for (int i = 0; i <arr.length; i++){
            newArr[i] = arr[i];
        }
        //将新数组的地址赋值给原有的数组变量
        arr = newArr;
复制代码
复制代码
     int[] arr = new int[]{1,2,3,4,5,6};
        
        //删除索引第四个的元素
        int deleteIndex = 4;
        //方式1  不新建数组
        for (int i = deleteIndex; i < arr.length - 1; i++){
            arr[i] = arr[i + 1];
        }
        arr[arr.length-1] = 0;
        
        //方式2  新建数组,比原有数组长度少一个
        int[] newArr = new int[arr.length - 1];
        for(int i = 0; i < deleteIndex; i++){
            newArr[i] = arr[i];
        }
        for(int i = deleteIndex; i < arr.length-1; i++){
            newArr[i] = arr[i+1];
        }
        arr = newArr;
复制代码
  • 数组的查找

顺序查找

优点: 算法简单   缺点: 效率低,执行的时间复杂度为O(n)

复制代码
     int[] arr = new int[]{34,65,23,6,36,62,74,13};
        int target = 6;
        //线性查找
        int i = 0;
        for(; i < arr.length; i++){
            if(target == arr[i]){
                system.out.println("找到了!"+target+",对应的位置是:"+i);
                break;
            }
        }
        if (i == arr.length){
            system.out.println("不好意思! 没有找到此元素!");
        }
复制代码

二分查找

优点: 执行效率高,执行的时间复杂度O(log2N)  缺点:相对顺序查找难一点

复制代码
     int[] arr = new int[]{2,4,6,9,11,18,32,57,74,82};
        int target = 11;
        //二分查找  必须有序数组
        int head = 0;// 默认的首索引
        int end = arr.length - 1;// 默认的尾索引
        boolean flag = false;
        while(head <= end){
            int middle = (head + end) / 2;
            if(target == arr[middle]){
                System.out.println("找到了!" + target + ",对应的位置为:" + middle);
                flag = true;
                break;
            }else if (target > arr[middle]){
                head = middle + 1;
            }else{
                end = middle - 1;
            }
        }
        if (!flag){
            System.out.println("不好意思!没有找到!");
        }    
复制代码
  •  数组的排序

 时间复杂度:分析关键字的比较次数和记录的移动次数

 (log 是以2为底)

空间复杂度: 分析算法中需要多少辅助内存。   一个算法的空间复杂度S(n) 定义为该算法所耗费的存储空间, 它也是问题规模n的函数。

稳定性:若两个记录A和B的关键字值相等,但排序后A、B的先后次序保持不变,则称这种排序算法是稳定的。

排序的分类:内部排序(内存中排序)   外部排序(外部存储设备+内存)

 冒泡排序

时间复杂度O(n^2)

基本思想:对待排序的元素从前向后依次比较相邻的两个元素,如果顺序不对则交换它们的位置,一轮比较下来,最大的元素就会“冒泡”到数组的末尾。

复制代码
     int[] arr = new int[]{34,2,76,67,15,95,57};
        //冒泡排序
        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]){
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
        // 遍历结果:
        for (int i = 0; i < arr. length; i++){
            System.out.print(arr[i] + " ");
        }
复制代码

快速排序

快速排序的时间复杂度O(nlog2n)!!

基本步骤:

  1. 首先选取待排序数组中一个元素作为基准元素,通常选择第一个元素或最后一个元素作为基准元素。

  2. 遍历数组,将小于基准元素的元素放到左边,大于等于基准元素的元素放到右边,此时数组被划分成了两个部分。

  3. 对左半部分和右半部分分别递归执行上述操作,直到排序完成。

复制代码
    public static void quickSort(int[] arr,int low,int high){
        int i,j,temp,t;
        if(low>high){
            return;
        }
        i=low;
        j=high;
        //temp就是基准位
        temp = arr[low];
 
        while (i<j) {
            //先看右边,依次往左递减
            while (temp<=arr[j]&&i<j) {
                j--;
            }
            //再看左边,依次往右递增
            while (temp>=arr[i]&&i<j) {
                i++;
            }
            //如果满足条件则交换
            if (i<j) {
                t = arr[j];
                arr[j] = arr[i];
                arr[i] = t;
            }
        }
        //最后将基准为与i和j相等位置的数字交换
         arr[low] = arr[i];
         arr[i] = temp;
        //递归调用左半数组
        quickSort(arr, low, j-1);
        //递归调用右半数组
        quickSort(arr, j+1, high);
    }
 
    public static void main(String[] args){
        int[] arr = {10,7,2,4,7,62,3,4,2,1,8,9,19};
        quickSort(arr, 0, arr.length-1);
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
复制代码

 Arrays数组工具类

Arrays类所在位置:处在java.util包下

  • boolean equals(int[] a, int[] b);  比较两个数组的元素是否依次相等

     // boolean equals(int[] a, int[] b); 比较两个数组的元素是否依次相等
        int[] arr1 = new int[]{1,2,3,4,5};
        int[] arr2 = new int[]{1,2,3,4,5};
        
        System.out.println(arr1 == arr2); //这一句比的是这两个数组的地址!!!
        //正确做法:
        boolean isEquals = Arrays.equals(arr1,arr2);
        System.out.println(isEquals);
  • String toString (int[] a); 输出数组元素信息

     // String toString(int[] a); 输出数组元素信息
        int[] arr1 = new int[]{1,2,3,4,5};

        System.out.println(arr1); //这里输出的实arr1的地址
        //正确做法:
        System.out.println(Arrays.toString(arr1));
  • void fill(int[] a, int val); 将指定值填充到数组之中

        // void fill(int[] a, int val); 将指定值填充到数组之中
        int[] arr1 = new int[]{1,2,3,4,5};

        Arrays.fill(arr1,10);
        System.out.println(Arrays.toString(arr1));
  • void sort (int[] a);使用快速排序算法对数组排序

        // void sort (int[] a);使用快速排序算法对数组排序
        int[] arr1 = new int[]{1,2,3,4,5};

        Arrays.sort(arr1);
        System.out.println(Arrays.toString(arr1));
  • int binarySearch(int[] a, int key);  二分查找

适用前提: 数组必须是有序的!    如果返回的索引是负数就是没找到!

        // int binarySearch(int[] a, int key);  二分查找
        int[] arr1 = new int[]{1,2,3,4,5};
        int index = Arrays.binarySearch(arr1,4);
        if (index >= 0 ){
            System.out.println("找到了!索引位置是:" + index);
        }else {
            System.out.println("未找到!");
        }

数组中的异常

> 数组角标越界的异常: ArrayIndexOutOfBoundsException

> 空指针的异常: NullPointerException

        // 数组角标越界的异常
        int[] arr = new int[10];
        //角标的有效范围:0-9
        System.out.println(arr[10]);  //越界
        System.out.println(arr[-1]);  //越界
复制代码
        // 数组空指针异常
        //情况1
        int[] arr1 = new int[10];
        arr1 = null;
        System.out.println(arr1[0]);  //空指针
        //情况2
        int[][] arr2 = new int[3][];
        System.out.println(arr2[0][1]);  //空指针
        //情况3
        String[] arr3 = new String[4];
        System.out.println(arr3[0].toString()); //arr3[0]是null 所以不可以调用里面的方法
复制代码

 

posted on   gjwqz  阅读(7)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示