一、數組是一種常見的數據結構,用來存儲同一類型值的集合java
二、數組就是存儲數據長度固定的容器,保證多個數據的數據類型要一致git
三、數組是一種順序存儲的線性表,全部元素的內存地址是連續的github
四、例如:new 一個int基本類型的數組array數組
int[] array = new int[]{11,22,33};
五、數組的優點與劣勢數據結構
/** * 元素的數量 */ protected int size; /** * 數組全部元素及內存地址指向 */ private E[] elements;
圖示結構:app
將動態數組與鏈表共同的屬性與方法抽取出,做爲抽象類,提升複用性ide
抽象父類接口——List
函數
public interface List<E> { //查無元素的返回標誌 int ELEMENT_NOT_FOUND = -1; /** * 元素的數量 * @return */ int size(); /** * 是否爲空 * @return */ boolean isEmpty(); /** * 設置index位置的元素 * @param index * @param element * @return 原來的元素ֵ */ E set(int index, E element); /** * 獲取index位置的元素 * @param index * @return */ E get(int index); /** * 是否包含某個元素 * @param element * @return */ boolean contains(E element); /** * 查看元素的索引 * @param element * @return */ int indexOf(E element); /** * 添加元素到尾部 * @param element */ void add(E element); /** * 在index位置插入一個元素 * @param index * @param element */ void add(int index, E element); /** * 刪除index位置的元素 * @param index * @return */ E remove(int index); /** * 刪除指定元素 * @param element * @return */ public E remove(E element); /** * 清除全部元素 */ void clear();
抽象父類AbstractList
是對接口List
的實現ui
public abstract class AbstractList<E> implements List<E> { /** * 元素的數量 */ protected int size; /** * 元素的數量 * @return */ public int size() { return size; } /** * 是否爲空 * @return */ public boolean isEmpty() { return size == 0; } /** * 是否包含某個元素 * @param element * @return */ public boolean contains(E element) { return indexOf(element) != ELEMENT_NOT_FOUND; } /** * 添加元素到尾部 * @param element */ public void add(E element) { add(size, element); } /** * 非法索引訪問數組異常 * @param index */ protected void outOfBounds(int index) { throw new IndexOutOfBoundsException("Index:" + index + ", Size:" + size); } /** * 索引檢查函數 * @param index */ protected void rangeCheck(int index) { if (index < 0 || index >= size) { outOfBounds(index); } } /** * 數組添加元素的索引檢查函數 * @param index */ protected void rangeCheckForAdd(int index) { //index > size,元素能夠添加在數組size位置,即數組尾部下一存儲單元 if (index < 0 || index > size) { outOfBounds(index); } } }
public class DynamicArray<E> extends AbstractList<E> { /** * 數組全部元素及內存地址指向 */ private E[] elements; //數組的默認初始化值 private static final int DEFAULT_CAPACITY = 10; /** * 帶參構造函數,參數是數組初始化值 * @param capacity */ public DynamicArray(int capacity) { //若是傳入的capacity>默認初始值,取capacity,不然取默認值 capacity = Math.max(capacity, DEFAULT_CAPACITY); //經過new Object[],動態數組能夠實現多對象化 elements = (E[]) new Object[capacity]; } /** * 構造函數,將數組初始化 */ public DynamicArray() { this(DEFAULT_CAPACITY); } /** * 設置index位置的元素值 * @param index * @param element * @return old */ public E set(int index,E element){ //檢查索引是否合法 rangeCheck(index); // E old = elements[index]; elements[index] = element; return old; } /** * 獲取數組index位置的元素 * @param index * @return elements[index]; */ public E get(int index){ rangeCheck(index); return elements[index]; } /** * 查看元素的索引 * @param element * @return */ public int indexOf(E element){ //若是元素爲空,單獨判斷,防止NPE if (element == null){ for (int i = 0;i < size;i++){ if (elements[i] == null) return i; } }else { //元素不爲空 for (int i = 0;i < size;i++){ if (element.equals(elements[i])) return i; } } //查無此元素 return ELEMENT_NOT_FOUND; } /** * 添加元素到數組指定位置 * @param index * @param element */ public void add(int index,E element){ //檢查索引是否合法 rangeCheckForAdd(index); //檢查數組容量是否足夠 ensureCapacity(size + 1); for (int i = size;i > index;i--){ elements[i] = elements[i - 1]; } elements[index] = element; size++; } /** * 刪除指定元素 * @param element * @return */ public E remove(E element){ //調用indexOf獲取索引,經過索引刪除指定元素 return remove(indexOf(element)); } /** * 刪除指定index位置的元素 * @param index * @return */ public E remove(int index){ //檢查索引是否合法 rangeCheck(index); E old = elements[index]; for (int i = index + 1;i < size;i++){ elements[i - 1] = elements[i]; } //將數組原來尾部最後的元素所在的位置置爲null,釋放原來地址引用對應的對象內存 elements[--size] = null; //檢測是否須要縮容 trim(); return old; } /** * 清除全部元素 */ public void clear() { for (int i = 0; i < size; i++) { elements[i] = null; } size = 0; } /** * 保證要有capacity的容量 * @param capacity */ private void ensureCapacity(int capacity){ int oldCapacity = elements.length; //若是數組容量足夠,return if (oldCapacity >= capacity) return; //不然的話,數組擴容,數組擴容1.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); E[] newElements = (E[]) new Object[newCapacity]; //將原有數組元素複製到新數組中 for (int i = 0;i < size;i++){ newElements[i] = elements[i]; } //指向新數組 elements = newElements; System.out.println(oldCapacity + "擴容爲" + newCapacity); } /** * 重寫toString函數,打印數組 * @return */ @Override public String toString() { // size=3, [99, 88, 77] StringBuilder string = new StringBuilder(); string.append("size=").append(size).append(", ["); for (int i = 0; i < size; i++) { if (i != 0) { string.append(", "); } string.append(elements[i]); } string.append("]"); return string.toString(); } }
在每次刪除數組元素時及清空數組時,進行縮容檢查this
/** * 若是內存使用比較緊張,動態數組有比較多的剩餘空間,能夠考慮進行縮容操做 * 例如:通過擴容後的數組很大,在通過刪除操做後,數組元素數量很少,而數組所佔空間夠大 * 好比剩餘空間佔總容量的一半時,就進行縮容 (規則能夠自定義) */ private void trim(){ int oldCapacity = elements.length; int newCapacity = oldCapacity >> 1; //若是元素的數量大於縮容後數組長度,或者小於初始量,不進行縮容操做 if (size >= (newCapacity) || size <= DEFAULT_CAPACITY) return;; // 剩餘空間還不少 E[] newElements = (E[]) new Object[newCapacity]; for (int i = 0; i < size; i++) { newElements[i] = elements[i]; } elements = newElements; System.out.println(oldCapacity + "縮容爲" + newCapacity); }
/** * 清除全部元素 */ public void clear() { // 數組清空,應該根據狀況縮容,避免內存浪費 if (elements != null && elements.length > DEFAULT_CAPACITY) { elements = (E[]) new Object[DEFAULT_CAPACITY]; }else { for (int i = 0; i < size; i++) { elements[i] = null; } } size = 0; }
我的能力有限,有不正確的地方,還請指正
文章爲原創,歡迎轉載,註明出處便可
本文的代碼已上傳github
,歡迎star