自已實現一個數組
前言:
最近開始學習資料結構,剛學到陣列,寫下此篇部落格記錄下學習內容。如文中有不對的地方還請大佬指出。
正文:
1.陣列(Array):陣列是一種線性表資料結構,它是一組連續的空間和相同的資料型別組成。
2.資料的時間複雜度分析:
1)插入:最好的情況為O(1),最壞的情況為O(n),均攤為O(n)。
2) 刪除:最好的情況為O(1),最壞的情況為O(n),均攤為O(n)。
3)查詢:最好的情況為O(1),最壞的情況為O(n),均攤為O(n)。
原因:
插入:如果在索引3處插入一個新的值20,因為陣列是一組連續的空間,為了保持資料的連續性,資料將會進行資料搬移動作,將索引3及後面的值向後移動,造成大量的時間消耗。最好的情況就是在陣列的最後一個位置進行插入操作,這樣就避免了大量的資料搬移。如果不需要資料的連續性,可以考慮將3處的值移動到陣列末尾處,然後在將值插入到3處,這樣就避免的資料的搬移。
刪除:跟插入相似,不過是將資料往前搬移。可以考慮將要刪除的值做個標記,等陣列記憶體不夠用時統一做刪除操作。
圖片是用excel製作的,有點醜。
查詢:陣列查詢需要遍歷,遍歷需要O(n)的時間。當需要查詢某個值時如果這個值剛好在下標0處那麼時間複雜度就為O(1),這種情況一般很少見。如果是排好序的陣列通過二分法查詢時間複雜度就是O(logn)。
3.陣列的優缺點
缺點:因為資料是一組連續的空間,所以當沒有連續的空間時,就沒有足夠的記憶體分配。例:當我們需要建立一個100M的陣列時,此時虛擬機器記憶體剛好只剩100M,但不是連續的,就會造成記憶體不夠分配。
優點:陣列支援隨機訪問(也就是直接通過下標訪問),時間複雜度為O(1)。
4.陣列的定址公式:array[i]_address = first_address + i * data_type_size; first_address是陣列第一個元素所在的記憶體地址,i是下標,data_type_size是資料型別大小。
例:比如說我們要找到下標3的記憶體地址,第一個元素的記憶體地址是1024,資料型別是int型別,int型別佔4個位元組。那麼array[3]_address = 1024 + 3 * 4;就是下標3的記憶體地址了。
5.下面開始用程式碼實現一個自已的陣列,我使用的是Java語言編寫的。
/** * @author zhouyun * @email [email protected] * @Description: 自定義陣列 * @Date 2018/12/22 17:28 * @Version 1.0 **/ public class CustomArray<E> { /** * 陣列 */ private E[] data; /** * 陣列元素的個數 */ private int size; /** * 指定大小的構造器 */ public CustomArray(int capacity){ //大於0才建立陣列 if(capacity > 0) { data = (E[]) new Object[capacity]; size = 0; }else { throw new IllegalArgumentException("Illegal Capacity: "+ capacity); } } /** * 預設陣列大小為10 */ public CustomArray(){ this(10); } /** * 獲取元素的個數 */ public int getSize(){ return size; } /** * 獲取陣列的容量 */ public int getCapacity(){ return data.length; } /** * 陣列元素是否為空 */ public boolean isEmpty(){ return size == 0; } /** * 向陣列末尾新增元素 */ public void addLast(E e){ add(size,e); } /** * 向陣列第一位新增元素 */ public void addFirst(E e){ add(0,e); } /** * 在指定索引處新增元素 */ public void add(int index,E e){ //陣列是否存滿 if(size == data.length){ throw new IllegalArgumentException("Array space is exhausted"); } //索引非法 if(index <0 || index > data.length){ throw new ArrayIndexOutOfBoundsException("Array index out of range: " + index); } //搬移資料 for (int i=size -1;i >= index;i--){ data[i + 1] = data[i]; } data[index] = e; size ++; } /** * 獲取指定索引處的值 */ public E get(int index){ //索引非法 if(index < 0 || index > data.length){ throw new ArrayIndexOutOfBoundsException("Array index out of range: " + index); } return data[index]; } /** * 修改指定索引處的值 */ public void set(int index,E e){ //索引非法 if(index <0 || index > data.length){ throw new ArrayIndexOutOfBoundsException("Array index out of range: " + index); } data[index] = e; } /** * 刪除指定索引處的值 */ public void remove(int index){ //索引非法 if(index <0 || index > data.length){ throw new ArrayIndexOutOfBoundsException("Array index out of range: " + index); } //資料搬移 for (int i = index + 1 ; i < size ; i++) { data[i-1] = data[i ]; } //將最後一個元素的值設定為null data[size -1 ] = null; size --; } /** * 刪除某一個元素 */ public boolean removeElement(E e){ //呼叫查詢方法,尋找元素的索引 //只刪除找到的第一個 int i = find(e); //找到則執行刪除操作 if(i != -1){ remove(i); return true; } return false; } /** * 查詢陣列中是否包含某個值 * 包含返回true,否則返回false */ public boolean contains(E e){ for (int i = 0; i < data.length; i++) { if(data[i].equals(e)){ return true; } } return false; } /** * 查詢指定內容的索引 * 如果未找到,返回-1 */ public int find(E e){ for (int i = 0; i < data.length; i++) { if(data[i].equals(e)){ return i; } } return -1; } /** * 重寫toString 方便列印 */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(String.format("Array: size=%d ,capacity=%d \n",size,data.length)); sb.append("["); for (int i=0;i<size;i++){ sb.append(data[i]); if(i != size -1 ){ sb.append(" , "); } } sb.append("]"); return sb.toString(); } } /** * @author zhouyun * @email [email protected] * @Description 自定義陣列測試類 * @Date 2018/12/22 22:28 * @Version 1.0 **/ public class CustomArrayTest { public static void main(String[] args) { CustomArray<Integer> customArray = new CustomArray(); for (int i = 0; i < customArray.getCapacity(); i++) { //向陣列末尾插入元素 customArray.addLast(i ); } //測試刪除 customArray.remove(2); //測試指定索引新增 customArray.add(9,10); //測試查詢 System.out.println("查詢結果: " + customArray.find(5 )); //測試獲取指定索引的值 System.out.println("指定索引位置的值: " + customArray.get(5 )); //測試包含 System.out.println("陣列中是否包含這個元素: " + customArray.contains(6)); //列印輸出陣列元素 System.out.println(customArray); } }