JAVA基础知识(三)——数组

数组

    • 数组
        • 一、数组的概述
          • [1.1 数组的定义](#1.1 数组的定义)
          • [1.2 数组的常见概念](#1.2 数组的常见概念)
          • [1.3 数组的特点](#1.3 数组的特点)
          • [1.4 数组的分类](#1.4 数组的分类)
        • 二、一维数组的使用
          • [2.1 一维数组的声明和初始化](#2.1 一维数组的声明和初始化)
          • [2.2 数组的基本使用](#2.2 数组的基本使用)
          • [2.3 数组元素的默认初始化值](#2.3 数组元素的默认初始化值)
          • [2.4 数组的内存解析](#2.4 数组的内存解析)
        • 三、多维数组的使用
          • [3.1 二维数组的理解](#3.1 二维数组的理解)
          • [3.2 二维数组的声明](#3.2 二维数组的声明)
          • [3.3 二维数组的引用](#3.3 二维数组的引用)
          • [3.4 二维数组的默认初始化值](#3.4 二维数组的默认初始化值)
          • [3.5 二维数组的内存分析](#3.5 二维数组的内存分析)
          • [3.6 二维数组的练习](#3.6 二维数组的练习)
        • 四、数组中常见的算法
          • [4.1 数组中涉及的常见算法](#4.1 数组中涉及的常见算法)
          • [4.2 二分法查找算法](#4.2 二分法查找算法)
          • [4.3 排序算法](#4.3 排序算法)
          • [4.4 冒泡排序](#4.4 冒泡排序)
          • [4.5 快速排序](#4.5 快速排序)
          • [4.6 各种内部排序方法性能比较](#4.6 各种内部排序方法性能比较)
          • [4.7 排序算法的选择](#4.7 排序算法的选择)
          • [4.8 Arrays工具类的使用](#4.8 Arrays工具类的使用)

数组

一、数组的概述

1.1 数组的定义

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

1.2 数组的常见概念
  • 数组名
  • 下标(或索引)
  • 元素
  • 数组的长度
1.3 数组的特点
  • 数组本身是引用数据类型,而数组中的元素可以是任何数据类型,包括基本数据类型和引用数据类型
  • 创建数据对象会在内存中开辟一整块连续的空间,而数组名中引用的是这块连续空间的首地址
  • 数组的长度一旦确定,就不能修改
  • 我们可以直接通过下标(或索引)的方式调用指定位置的元素,速度很快。
1.4 数组的分类
  • 按照维度:一维数组、二维数组、三维数组、...
  • 按照元素的数据类型分:基本数据类型元素的数组、引用数据类型元素的数组(即对象数组)

二、一维数组的使用

2.1 一维数组的声明和初始化
  • 静态初始化:数组的初始化和数组元素的赋值操作同时进行
  • 动态初始化:数组的初始化和数组元素的赋值操作分开进行
java 复制代码
           //1. 一维数组的声明和初始化
        int num; //声明
        num = 10;
        int id = 1001;// 声明+ 初始化

        int[] ids;//声明
        //1.1 静态初始化:数组的初始化和数组元素的赋值操作同时进行
        ids = new int[]{1001, 1002, 1003, 1004};

        int id2[] = new int[]{1001, 1002, 1003, 1004};
        
        //1.2 动态初始化:数组的初始化和数组元素的赋值操作分开进行
        String[] names = new String[5];
  • 错误的写法
java 复制代码
        int[] arr1 = new int[];
        
        int[5] arr2 = new int[5];
        
        int[] arr3 = new int[3]{1, 2,4};
2.2 数组的基本使用
  • 定义并用运算符new为之分配空间后,才可以引用数组中的每个元素;
  • 数组元素的引用方式:数组名[数组元素下标 ]
    • 数组元素下标可以是整型常量或整型表达式。如a[3] , b[i] , c[6*i];
    • 数组元素下标从0开始;长度为n的数组合法下标取值范围: 0 --->n-1;如int a[]=new int[3]; 可引用的数组元素为a[0]、a[1]、a[2]
  • 每个数组都有一个属性length指明它的长度,例如:a.length 指明数组a的长度(元素个数)
    • 数组一旦初始化,其长度是不可变的
java 复制代码
 //总结:数组一旦初始化完成,其长度就确定了
 
//(2)如何调用数组指定位置的元素:通过索引的方式调用
//数组的索引是从0开始的,到数组的长度-1结束
names[0] = "张三";
names[1] = "李四";
names[2] = "王五";
names[3] = "赵六";
names[4] = "孙七";
 
//3、如何获取数组的长度
//属性 length
System.out.println(ids.length);
System.out.println(names.length);
 
//4、如何遍历数组
for (int i = 0; i < ids.length; i++){
    System.out.println(ids[i]);
}
 
for (int i = 0; i < names.length; i++){
    System.out.println(names[i]);
}
2.3 数组元素的默认初始化值

数组是引用类型,它的元素相当于类的成员变量,因此数组一经分配空间,其中的每个元素也被按照成员变量同样的方式被隐式初始化。

数组元素类型 元素默认初始值
byte 0
short 0
int 0
long 0L
float 0.0F
double 0.0
char 0或写:'\u0000' (表现为空)
boolean false
引用数据类型 null
java 复制代码
        System.out.println("----------byte数组初始化值-----------");
        byte[] byteArray = new byte[1];
        for (int i = 0; i < byteArray.length; i++) {
            System.out.println(byteArray[i]);
        }
        System.out.println("----------short数组初始化值-----------");
        short[] shortArray = new short[1];
        for (int i = 0; i < shortArray.length; i++) {
            System.out.println(shortArray[i]);
        }
        System.out.println("----------int数组初始化值-----------");
        int[] intArray = new int[1];
        for (int i = 0; i < intArray.length; i++) {
            System.out.println(intArray[i]);
        }
        System.out.println("----------long数组初始化值-----------");
        long[] longArray = new long[1];
        for (int i = 0; i < longArray.length; i++) {
            System.out.println(longArray[i]);
        }
        System.out.println("----------float数组初始化值-----------");
        float[] floatArray = new float[1];
        for (int i = 0; i < floatArray.length; i++) {
            System.out.println(floatArray[i]);
        }
        System.out.println("----------double数组初始化值-----------");
        double[] doubletArray = new double[1];
        for (int i = 0; i < doubletArray.length; i++) {
            System.out.println(doubletArray[i]);
        }
        System.out.println("----------char数组初始化值-----------");
        char[] charArray = new char[1];
        for (int i = 0; i < charArray.length; i++) {
            System.out.println(charArray[i]);
        }
        System.out.println("----------boolean数组初始化值-----------");
        boolean[] booleanArray = new boolean[1];
        for (int i = 0; i < booleanArray.length; i++) {
            System.out.println(booleanArray[i]);
        }
        System.out.println("----------引用类型数组初始化值-----------");
        String[] stringArray = new String[1];
        for (int i = 0; i < stringArray.length; i++) {
            System.out.println(stringArray[i]);
        }
java 复制代码
----------byte数组初始化值-----------
0
----------short数组初始化值-----------
0
----------int数组初始化值-----------
0
----------long数组初始化值-----------
0
----------float数组初始化值-----------
0.0
----------double数组初始化值-----------
0.0
----------char数组初始化值-----------
 
----------boolean数组初始化值-----------
false
----------引用类型数组初始化值-----------
null
2.4 数组的内存解析
  • jvm示意图
  • 数组内存解析示例:
java 复制代码
int[] arr = new int[]{1,2,3};
String[] arr1 = new String[4];
arr1[1] = "刘德华";
arr1[2] = "张学友";
arr1 = new String[3];

三、多维数组的使用

3.1 二维数组的理解
  • Java 语言里提供了支持多维数组的语法
  • 如果说可以把一维数组当成几何中的线性图形,那么二维数组就相当于是一个表格,像右图Excel中的表格一样。
  • 对于二维数组的理解,我们可以看成是一维数组array1又作为另一个一维数组array2的元素而存在。其实,从数组底层的运行机制来看,其实没有多维数组。
  • 二维数组:数组中的数组。
3.2 二维数组的声明
java 复制代码
         //1.二维数组的声明和初始化
        int[] arr =  new int[]{1, 2, 3};//一维数组
        //静态初始化
        int[][] arr1 =  new int[][]{{1,2,3}, {4,5,6}, {7,8}};
        //动态初始化
        String[][] arr2 = new String[3][2];

        String arr3[][] = new String[3][2];
        String[] arr4[] = new String[3][2];
  • 非法
java 复制代码
int[][]arr = new int[][3]; //非法
3.3 二维数组的引用
java 复制代码
//静态初始化
int[][] arr1 = new int[][]{{1, 2, 3}, {4, 5, 6}, {7, 8}};
//动态初始化1
int[][] arr2 = new int[3][2];
//动态初始化2
int[][] arr3 = new int[3][];
 
//这样也是正确的 但是不推荐
//        int arr4[][];
//        int[] arr4[];
 
//2、如何调用数组指定位置的元素
System.out.println(arr1[0][1]);//2
System.out.println(arr2[1][1]);//0
 
arr3[1] = new int[2];
System.out.println(arr3[1][1]);//0
 
//3、获取数组的长度
System.out.println(arr1.length);//3
System.out.println(arr1[0].length);//3
System.out.println(arr1[1].length);//3
 
//4、如何遍历二维数组
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();
}
3.4 二维数组的默认初始化值
java 复制代码
        //int类型
        int[][] arr = new int[3][];
        System.out.println(arr[0]);// null
// System.out.println(arr[0][0]); //NullPointerException
        System.out.println(arr); //[[I@1b6d3586

        int[][] arr1 = new int[3][4];
        System.out.println(arr1[0]);// [I@1b6d3586 地址值
        System.out.println(arr1[0][0]); //0
        System.out.println(arr1); //[[I@74a14482

//float类型
        float[][] arr3 = new float[3][4];
        System.out.println(arr3[0]);// [F@1540e19d 地址值
        System.out.println(arr3[0][0]); //0.0

//String类型
        String[][] arr4 = new String[3][4];
        System.out.println(arr4[0]);// [Ljava.lang.String;@677327b6 地址值
        System.out.println(arr4[0][0]); //null
3.5 二维数组的内存分析
java 复制代码
int[][] arr1 = int[4][];
arr1[1] = new int[]{1,2,3};
arr1[2] = new int[4];
arr1[2][1] = 30;

int[4][] 中int[0]的值为null, 是因为此时的int[]引用类型没有赋值 所以是null

3.6 二维数组的练习
  • x 表示int[] y 表示int[][] y[0] 表示int[]
  • 一维数组:int[] x 或者int x[];
  • 二维数组:int[][] y 或者int[] y[]或者int y[][]
java 复制代码
注意:x 表示int[] y 表示int[][] y[0] 表示int[]
声明:int[] x,y[];在给x,y变量赋值以后,以下选项允许通过编译的是:
a) x[0] = y;//错误 类型不一致 x是一维数组 y是二维数组
b) y[0] = x; //编译通过
c) y[0][0] = x;//y[0][0]表示的是值, x表示的是地址值
d) x[0][0] = y;//错误
e) y[0][0] = x[0];//编译通过
f) x = y; //错误 x表示int[],y表示int[][]

四、数组中常见的算法

4.1 数组中涉及的常见算法
  • 数组元素的赋值(杨辉三角、回形数等)
  • 求数值型数组中的最大值、最小值、平均数、总和等。
  • 数组的复制、反转、查找(线性查找、二分法查找)
  • 数组元素的排序算法
4.2 二分法查找算法
java 复制代码
    public static void main(String[] args) {
       int[] array = {1,4,5,23,45,67};
       int targetNum = -67;
       binarySearch(array, targetNum);
    }

    public static void binarySearch(int[] source, int targetNum) {
           int head = 0;
           int end =  source.length -1;
           while(head <= end) {
               int middle = (head+end)/2;
               if (source[middle] > targetNum) {
                   end = middle - 1;
               } else if (source[middle] < targetNum) {
                   head = middle + 1;
               } else {
                   System.out.println("数据找到了" + source[middle] + "当前位置为" + middle);
                   break;
               }
       }
       if (head > end) {
           System.out.println("数据未找到" + targetNum);
       }
    }
4.3 排序算法
  • 排序:假设含有n个记录的序列为{R1,R2,...,Rn},其相应的关键字序列为{K1,K2,...,Kn}。将这些记录重新排序为{Ri1,Ri2,...,Rin},使得相应的关键
    字值满足条Ki1<=Ki2<=...<=Kin,这样的一种操作称为排序。
  • 通常来说,排序的目的是快速查找。
  • 衡量排序算法的优劣:
    • 时间复杂度:分析关键字的比较次数和记录的移动次数
    • 空间复杂度:分析排序算法中需要多少辅助内存
    • 稳定性:若两个记录A和B的关键字值相等,但排序后A、B的先后次序保持不变,则称这种排序算法是稳定的。
  • 排序算法分类
    • 内部排序:整个排序过程不需要借助于外部存储器(如磁盘等),所有排序操作都在内存中完成。
    • 外部排序:参与排序的数据非常多,数据量非常大,计算机无法把整个排序过程放在内存中完成,必须借助于外部存储器(如磁盘)。外部排序最常见的是多路归并排序。可以认为外部排序是由多次内部排序组成。
  • 十大内部排序算法
    • 选择排序:直接选择排序、堆排序
    • 交换排序: 冒泡排序、快速排序
    • 插入排序:直接插入排序、折半插入排序、Shell排序
    • 归并排序
    • 桶式排序
    • 基数排序
  • 算法的5大特征
4.4 冒泡排序
  • 介绍

    冒泡排序的原理非常简单,它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。

  • 排序思想

    • 比较相邻的元素。如果第一个比第二个大(升序),就交换他们两个。
    • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
    • 针对所有的元素重复以上的步骤,除了最后一个。
    • 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较为止。
java 复制代码
//冒泡排序 
 public static void bubbleSort(int[] source) {
        for (int i = 0; i < source.length; i++) {
            for (int i1 = i + 1; i1 < source.length; i1++) {
                if (source[i] < source[i1]) {
                    int temp = source[i];
                    source[i] = source[i1];
                    source[i1] = temp;
                    continue;
                }
            }
        }
        for (int i : source) {
            System.out.print(i + " ");
        }
    }

    //改进
    public static void bubbleSortUpgrade(int[] source) {
        for (int i = 0; i < source.length-1; i++) {//最后一个数不用在继续比较啦
            for (int i1 = i + 1; i1 < source.length-1-i; i1++) {//不用在和之前的数据去进行比较啦
                if (source[i] < source[i1]) {
                    int temp = source[i];
                    source[i] = source[i1];
                    source[i1] = temp;
                    continue;
                }
            }
        }
        for (int i : source) {
            System.out.print(i + " ");
        }
    }
//数组反转 方式一
    public static void arrayInversion(int[] source) {
        int[] newSource = new int[source.length];
        for (int i = source.length - 1,j=0; i >= 0; i--,j++) {
            newSource[j] = source[i];
        }
        for (int i : newSource) {
            System.out.print(i + " ");
        }
    }
    
    //数组反转 方式二
    public static void arrayInversionTwo(int[] source) {
        for (int i = 0; i < source.length/2; i++) {
            int temp = source[i];
            source[i] = source[source.length-i-1];
            source[source.length-i-1] = temp;
        }
        for (int i : source) {
            System.out.print(i + " ");
        }
    }
//获取最大值
    public static void getArrayMax(int[] source) {
        int max = source[0];
        for (int i = 0; i < source.length; i++) {
            if (max < source[i]) {
                max = source[i];
            }
        }
        System.out.println("max = " + max);
    }
//获取最小值
    public static void getArrayMin(int[] source) {
        int min = source[0];
        for (int i = 0; i < source.length; i++) {
            if (min > source[i]) {
                min = source[i];
            }
        }
        System.out.println("min = " + min);
    }
4.5 快速排序
  • 介绍
    快速排序通常明显比同为O(nlogn)的其他算法更快,因此常被采用,而且快排采用了分治法的思想,所以在很多笔试面试中能经常看到快排的影子。可见掌握快排的重要性。
    快速排序(Quick Sort)由图灵奖获得者Tony Hoare发明,被列为20世纪十大算法之一,是迄今为止所有内排序算法中速度最快的一种。冒泡排序的升级版,交换排序的一种。快速排序的时间复杂度为O(nlog(n))。
  • 排序思想:
    从数列中挑出一个元素,称为"基准"(pivot),
    重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
    递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
    递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
4.6 各种内部排序方法性能比较
  • 从平均时间而言:快速排序最佳。但在最坏情况下时间性能不如堆排序和归并排序。
  • 从算法简单性看:由于直接选择排序、直接插入排序和冒泡排序的算法比较简单,将其认为是简单算法。对于Shell排序、堆排序、快速排序和归并排序算法,其算法比较复杂,认为是复杂排序。
  • 从稳定性看:直接插入排序、冒泡排序和归并排序时稳定的;而直接选择排序、快速排序、 Shell排序和堆排序是不稳定排序
  • 从待排序的记录数n的大小看,n较小时,宜采用简单排序;而n较大时宜采用改进排序。
4.7 排序算法的选择
  • 若n较小(如n≤50),可采用直接插入或直接选择排序。当记录规模较小时,直接插入排序较好;否则因为直接选择移动的记录数少于直
    接插入,应选直接选择排序为宜。
  • 若文件初始状态基本有序(指正序),则应选用直接插入、冒泡或随机的快速排序为宜;
  • 若n较大,则应采用时间复杂度为O(nlgn)的排序方法:快速排序、堆排序或归并排序。
4.8 Arrays工具类的使用

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

方法 作用
boolean equals(boolean[] a, boolean[] a2) 判断两个数组是否相等
String toString(int[] a) 输出数组信息
void fill(int[] a, int val) 将指定值填充到数组中
void sort(int[] a) 对数组进行排序
int binarySearch(int[] a, int key) 对排序后的数组进行二分法检索指定的值
java 复制代码
int[] array = {99,76,64,43,33,32,32,21,0,-98};
       int[] array1 = {99,76,64,43,33,32,32,21,0,-98};

       int[] array3 = {99};
      //  System.out.println(Arrays.equals(array3, array2));
        System.out.println(Arrays.equals(array1, array));
        System.out.println(Arrays.toString(array));

        System.out.println("------------填充之前--------------");
        Arrays.fill(array, 156);
        Arrays.fill(array, 0, 3, 157);
        System.out.println(Arrays.toString(array));
        System.out.println("------------填充之后--------------");

        System.out.println("------------排序前--------------");
        Arrays.sort(array1);
        Arrays.sort(array1);
        System.out.println(Arrays.toString(array1));
        System.out.println("------------排序之后--------------");
       // int[] array2 = {99,76,64,43,33,32,21,0,-98};
        int[] array2 = {-98,0,21,32,33,43,64,76,99};
        System.out.println(Arrays.binarySearch(array2, 33));//有序的数组,且从小到大排列
        System.out.println(Arrays.binarySearch(array2, 64));
        //System.out.println(Arrays.binarySearch(array2, 3));
相关推荐
渣哥18 小时前
原来 Java 里线程安全集合有这么多种
java
间彧18 小时前
Spring Boot集成Spring Security完整指南
java
间彧19 小时前
Spring Secutiy基本原理及工作流程
java
数据智能老司机19 小时前
精通 Python 设计模式——创建型设计模式
python·设计模式·架构
Java水解20 小时前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
数据智能老司机20 小时前
精通 Python 设计模式——SOLID 原则
python·设计模式·架构
c8i1 天前
django中的FBV 和 CBV
python·django
c8i1 天前
python中的闭包和装饰器
python
洛小豆1 天前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试
前端小张同学1 天前
服务器上如何搭建jenkins 服务CI/CD😎😎
java·后端