【總結】
- 這一篇的四個數據結構都是線性數據結構。
- 動態數組,棧,隊列三種數據結構的底層,其實都是依託靜態數組,靠resize來解決固定容量問題。
【數組】
定義:數組data,數組中元素的個數size,容量capacity
public class Array{
private int[] data;
private int size;
public Array(int capacity){ // 初始化data和size
data = new int[capacity];
size = 0;
}
}
(這裏定義的是一個int型的數組,實際使用中可以使用泛型來定義數組,泛型就是定義的時候不指定類型,用的時候再給定,注意:泛型不可以使用基本的數據類型。)
- 增(添加):
- 順序添加:data[size] = value, size++;
- 指定位置添加:後面的元素先依次後移,然後將元素插入,size+1。
- 刪(刪除)
- 刪除指定位置的元素:後面的元素依次向前移一位,維護size。
- 刪除指定元素(elem):遍歷,找到後刪除
- 改(修改):
- 修改指定位置的元素(elem):data[index] = elem
- 查(查找):如果查找指定下標位置的元素,O(1),如果查找指定元素,O(n)。
動態數組
解決普通數組容量無法伸縮的問題。可以定義一個resize函數,在添加元素的時候新增判斷,如果數組已經佔滿,則擴充數組;在刪除元素的時候判斷,如果數組有3/4爲空,可以刪除縮減一半空間。(爲了減少複雜度震盪)
if(size == capacity)
resize(2 * capacity); // 當數組滿的時候,擴容
//需要在定義數組的類中定義private的resize函數,resize實現的功能是開闢一個更大的空間,並將原來的元素複製到新空間。
if(size == capacity / 4)
resize(capacity / 2); // 當數組有3/4空閒的時候,縮容(只縮一半,Lazy的做法,減少複雜度震盪)
- 增 :O(n)(最壞情況) 均攤時間複雜度爲O(1)
- 刪 :O(n)(最壞情況)均攤時間複雜度爲O(1)
- 改 :已知索引O(1),未知索引O(n)
- 查 :已知索引O(1),未知索引O(n)
resize的複雜度分析:均攤時間複雜度,每當數組塞滿了纔會觸發一次resize操作,將這個操作均攤在每一次添加的過程中,相當於每次添加元素的複雜度爲O(2)=O(1).
【棧——先進後出】
- 添加(c++中的push_back):O(1)
- 彈出(pop()):O(1)
- 查看棧頂元素(peek()):O(1)
棧可以使用數組,鏈表來實現:
- 使用鏈表來實現棧:(鏈表是動態數據結構,在鏈表頭添加,刪除和修改的複雜度爲O(1)),所以用鏈表實現棧的時候,將鏈表頭當作棧頂。
- 數組棧耗時的地方是:數組棧要時不時的resize數組容量,鏈表棧耗時的地方是:不停的創建node比較耗時。
【隊列——先進先出】
- 入隊(enqueue):O(1)
- 出隊(dequeueu):O(n) (將頭部的元素取出後,後面的元素順序往前移一位)
- 查看隊列頭部元素(getFront()):O(1)
循環隊列
爲了解決隊列的出隊複雜度太高的問題(O(n))。而使用循環隊列可以使得出隊的複雜度爲O(1)
front = tail 隊列爲空,(tail + 1) % capacity = front 隊列滿
- 入隊(enqueue):O(1)
- 出隊(dequeueu):O(1)
- 查看隊列頭部元素(getFront()):O(1)
雙端隊列
python中的雙端隊列用法:
import queue
q = queue.deque()
q.append(item) # 右邊進
q.pop() # 右邊出
q.appendleft(item) # 左邊進
q.popleft() # 左邊出
【鏈表】
鏈表是一種動態的數據結構,在鏈表中添加虛擬頭節點,可以方便使用。鏈表的增刪改查操作複雜度都是O(n)。(如果在鏈表頭添加,修改和刪除,複雜度爲O(1))
- 添加元素 O(n)
- 在鏈表頭添加元素(實現起來最簡單,無需遍歷鏈表):O(1)
- 在鏈表中間添加元素:O(n)
- 在鏈表末尾添加元素:O(n)
- 查找元素 O(n)
- get(index),查詢鏈表index位置的節點:需要遍歷
- get(elem),查找鏈表中是否含有elem節點:需要遍歷
- 修改元素,set(index),設置index位置的節點值。O(n)
- 刪除元素, 要找到待刪節點的前一個節點,修改其next指針。O(n)
鏈表實現棧
鏈表是動態數據結構,在鏈表頭添加,刪除和修改元素的複雜度爲O(1),
所以用鏈表實現棧的時候,將鏈表頭當作棧頂。
數組棧耗時的地方是:數組棧要時不時的resize數組容量,鏈表棧耗時的地方是:不停的創建node比較耗時。
帶有尾指針的鏈表實現隊列
帶有尾指針的鏈表,可以實現添加元素的複雜度降爲O(1).
head在鏈表頭,tail在鏈表尾,尾部複雜入隊,頭部負責出隊,這樣刪除和添加的複雜度都是O(1),可以實現隊列。