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

数组

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

数组

一、数组的概述

1.1 数组的定义

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

JAVA基础知识(三)——数组_第1张图片

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

二、一维数组的使用

2.1 一维数组的声明和初始化
  • 静态初始化:数组的初始化和数组元素的赋值操作同时进行
  • 动态初始化:数组的初始化和数组元素的赋值操作分开进行
           //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];

  • 错误的写法
        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的长度(元素个数)
    • 数组一旦初始化,其长度是不可变的
 //总结:数组一旦初始化完成,其长度就确定了
 
//(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
        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]);
        }
----------byte数组初始化值-----------
0
----------short数组初始化值-----------
0
----------int数组初始化值-----------
0
----------long数组初始化值-----------
0
----------float数组初始化值-----------
0.0
----------double数组初始化值-----------
0.0
----------char数组初始化值-----------
 
----------boolean数组初始化值-----------
false
----------引用类型数组初始化值-----------
null
2.4 数组的内存解析
  • jvm示意图
    JAVA基础知识(三)——数组_第2张图片
  • 数组内存解析示例:
int[] arr = new int[]{1,2,3};
String[] arr1 = new String[4];
arr1[1] = "刘德华";
arr1[2] = "张学友";
arr1 = new String[3];

JAVA基础知识(三)——数组_第3张图片

三、多维数组的使用

3.1 二维数组的理解
  • Java 语言里提供了支持多维数组的语法
  • 如果说可以把一维数组当成几何中的线性图形,那么二维数组就相当于是一个表格,像右图Excel中的表格一样。
  • 对于二维数组的理解,我们可以看成是一维数组array1又作为另一个一维数组array2的元素而存在。其实,从数组底层的运行机制来看,其实没有多维数组。
  • 二维数组:数组中的数组。
3.2 二维数组的声明
         //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];
  • 非法
int[][]arr = new int[][3]; //非法
3.3 二维数组的引用
//静态初始化
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 二维数组的默认初始化值
        //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 二维数组的内存分析
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
JAVA基础知识(三)——数组_第4张图片

3.6 二维数组的练习
  • x 表示int[] y 表示int[][] y[0] 表示int[]
  • 一维数组:int[] x或者int x[];
  • 二维数组:int[][] y 或者int[] y[]或者int y[][]
注意: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 二分法查找算法
    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);
       }
    }

JAVA基础知识(三)——数组_第5张图片

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

JAVA基础知识(三)——数组_第6张图片

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

  • 排序思想

    • 比较相邻的元素。如果第一个比第二个大(升序),就交换他们两个。
    • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
    • 针对所有的元素重复以上的步骤,除了最后一个。
    • 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较为止。
//冒泡排序 
 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)中,它至少会把一个元素摆到它最后的位置去。

JAVA基础知识(三)——数组_第7张图片

4.6 各种内部排序方法性能比较

JAVA基础知识(三)——数组_第8张图片

  • 从平均时间而言:快速排序最佳。但在最坏情况下时间性能不如堆排序和归并排序。
  • 从算法简单性看:由于直接选择排序、直接插入排序和冒泡排序的算法比较简单,将其认为是简单算法。对于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) 对排序后的数组进行二分法检索指定的值
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));

你可能感兴趣的:(java,java,python,开发语言)