數據結構之數組詳解

數組(Array)是由相同類型的元素(element)集合組成的固定長度(Size)的一種數據結構。在內存中是連續存儲的,所以能夠經過索引(Index)計算出某個元素的地址。
下面介紹都是已java爲示例。對於沒有詳細瞭解過的  相信有所收穫。
 

基礎知識

聲明

type arrayName[] 或者 type[] arrayName。
如:
int arrInt[] 或者 int[] arrInt
聲明過程,只是告訴編譯器: arrInt變量保存了一個int類型的數組。這個過程並無分配內存。

new分配內存

分配內存須要經過new完成,同時指明類型和數組大小。
如:
int[] arrInt = new int[4];
數組中元素經過new分配後自動完成初始化,通常有幾種: 數字類型初始化爲0(如:int/byte/short/long初始化爲0,float/double初始化爲0.0), 布爾型初始化爲false(boolean初始化爲false), String或者其餘對象類型初始化爲null
數組賦值也有兩種
int[] arrInt = {1,3,5,7};
或
int[] arrInt = new int[4];
arrInt[0] = 1;
arrInt[1] = 3;
arrInt[2] = 5;
arrInt[3] = 7;

 示意圖以下:java

多維數組

多維數組相似,即數組中的元素也是數組。如
int[][] arrInt = {{1,3,5},{2,4,6},{0,10,20}};

示意圖以下:數組

 
 
 

數組特色

 

  1. 索引(即下標) 通常從0開始,如java, C/C++。
  2. 長度固定,在申請時長度固定。內存連續,在內存中則是申請一塊連續的固定大小的空間。
  3. 數組有一維數組和多維數組,數組元素能夠是基本數據類型(Primitive),也能夠是對象引用(Reference)。
  4. 隨機訪問,可以根據位置(下標)直接訪問到元素。

 

注:
基本數據類型和對象引用數據類型
Primitive類型在java中有八種(具體內容後續整理),Primitive類型在內存位置直接存入實際的值,引用對象的內存分配是在堆上(Heap)。
Primitive類型: boolean、char、byte、short、int、long、float、double
數組下標從0開始
數組變量引用 指向了數組實際分配的連續內存的開始地址 即 第一個元素的地址(firstAdrr)數組下標(index)即偏移量。假使每一個元素大小爲size.
那麼數組元素位置計算:firstAdrr+index*size。
因此大部分語言數組下標是0開始。若是從1開始,計算位置時偏移量要減1操做,多了一步運算。
 

數組關聯的Class對象

每一個數組有一個關聯的Class對象,與其餘相同類型數組共享。
如: JNI中傳遞的參數常常看到:I表示int類型,[ 表示一個數組,[I 即int數組。
System.out.println("int array:" + new int[3].getClass());
System.out.println("int array:" + new int[3].getClass().getSuperclass());
System.out.println("String array:" + new String[3].getClass());
System.out.println("boolean array:" + new boolean[3].getClass());
結果爲:
int array:class [I
int array super:class java.lang.Object
String array:class [Ljava.lang.String;
boolean array:class [Z

 

數組的拷貝

一維數組拷貝

一維數組的clone()是 深度拷貝,拷貝了數組內的原始數據到新數組,而不是引用的複製。
 如:
int arrInt[] = {1,2,3};
 
int arrClone[] = arrInt.clone();
arrClone[1] = 5;
  
System.out.println(arrInt == arrClone);
  
for (int i = 0; i < arrClone.length; i++) {
    System.out.println(arrInt[i]+" "+arrClone[i]);
}
結果爲:
false
1 1
2 5
3 3

示意圖以下: 數據結構

多維數組拷貝

但多維數組則不是這樣。如:
int arrInt[][] = {{1,2,3},{4,5,6}};
        
int[][] arrClone = arrInt.clone();
arrClone[0][1] = 50;
arrInt[0][1] = 100;
  
System.out.println(arrInt == arrClone);
System.out.println(arrInt[0] == arrClone[0]);
  
for (int i = 0; i < arrInt.length; i++) {
    for (int j = 0; j < arrInt[i].length; j++) {
        System.out.println(arrInt[i][j]+" "+arrClone[i][j]);
    }
    
}
結果爲:
false
true
1 1
100 100
3 3
4 4
5 5
6 6

 示意圖以下:spa

 
 
 

數組操做

插入

如圖, 向數組中插入一個元素,插入位置及以後的全部元素都須要向後挪動一位來完成插入操做。
若是數組已經滿了(或者保證數組長度與元素個數一致),則只能建立一個新的數組(長度增長的)來完成插入操做。
時間複雜度上,最好的是數組未滿插入到最後 只需直接插入,操做一次(O(1))。最壞是插入到第一位,須要操做N次。
平均時間複雜度,(1 + 2 + ... + n) / n ~= O(n)
 
這是一個簡單的插入示例。在現有數組的position位置插入value值,首先建立了一個新數組(長度+1),依次填入數據。
private int[] insertArr(int[] srcArr, int position, int value) {
    if (position < 0 || position >= srcArr.length) return null;
    int[] desArr = new int[srcArr.length+1];
    System.arraycopy(srcArr, 0, desArr, 0, position);
    desArr[position] = value;
    System.arraycopy(srcArr, position, desArr, position+1, srcArr.length-position);
    return desArr;
}

 

刪除

相似插入的反向操做, 刪除某個元素,該位置及以後的全部元素 向前挪一位。
若是要保證數組長度與數組元素個數一致,則也須要從新建立一個(長度減少的)數組來完成。
示意圖:
 

查找

查找某一元素位置,只能一位位的遍歷查找了。
 

訪問

對於某位置的元素,直接讀取或修改 就能夠了。數組是隨機訪問的。
 

時間複雜度總結

最後整理個表格,上述操做的時間複雜度大體以下,很容易理解就不詳細解釋了。code

操做
平均時間複雜度
最壞條件時間複雜度
插入
O(n)
O(n)
刪除
O(n)
O(n)
查找
O(n)
O(n)
訪問
O(1)
O(1)
相關文章
相關標籤/搜索