【玩轉數據結構Part1】數組/棧/隊列/鏈表

【總結】

  • 這一篇的四個數據結構都是線性數據結構。
  • 動態數組,棧,隊列三種數據結構的底層,其實都是依託靜態數組,靠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型的數組,實際使用中可以使用泛型來定義數組,泛型就是定義的時候不指定類型,用的時候再給定,注意:泛型不可以使用基本的數據類型。

  1. 增(添加):
  • 順序添加:data[size] = value, size++;
  • 指定位置添加:後面的元素先依次後移,然後將元素插入,size+1。
  1. 刪(刪除)
  • 刪除指定位置的元素:後面的元素依次向前移一位,維護size。
  • 刪除指定元素(elem):遍歷,找到後刪除
  1. 改(修改):
  • 修改指定位置的元素(elem):data[index] = elem
  1. 查(查找):如果查找指定下標位置的元素,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的做法,減少複雜度震盪)
  1. 增 :O(n)(最壞情況) 均攤時間複雜度爲O(1)
  2. 刪 :O(n)(最壞情況)均攤時間複雜度爲O(1)
  3. 改 :已知索引O(1),未知索引O(n)
  4. 查 :已知索引O(1),未知索引O(n)
    resize的複雜度分析:均攤時間複雜度,每當數組塞滿了纔會觸發一次resize操作,將這個操作均攤在每一次添加的過程中,相當於每次添加元素的複雜度爲O(2)=O(1).

【棧——先進後出】

  1. 添加(c++中的push_back):O(1)
  2. 彈出(pop()):O(1)
  3. 查看棧頂元素(peek()):O(1)

棧可以使用數組,鏈表來實現:

  • 使用鏈表來實現棧:(鏈表是動態數據結構,在鏈表頭添加,刪除和修改的複雜度爲O(1)),所以用鏈表實現棧的時候,將鏈表頭當作棧頂。
  • 數組棧耗時的地方是:數組棧要時不時的resize數組容量,鏈表棧耗時的地方是:不停的創建node比較耗時。

【隊列——先進先出】

  1. 入隊(enqueue):O(1)
  2. 出隊(dequeueu):O(n) (將頭部的元素取出後,後面的元素順序往前移一位)
  3. 查看隊列頭部元素(getFront()):O(1)

循環隊列

爲了解決隊列的出隊複雜度太高的問題(O(n))。而使用循環隊列可以使得出隊的複雜度爲O(1)
front = tail 隊列爲空,(tail + 1) % capacity = front 隊列滿
在這裏插入圖片描述

  1. 入隊(enqueue):O(1)
  2. 出隊(dequeueu):O(1)
  3. 查看隊列頭部元素(getFront()):O(1)

雙端隊列

python中的雙端隊列用法:

import queue

q = queue.deque()
q.append(item) # 右邊進
q.pop() # 右邊出
q.appendleft(item) # 左邊進
q.popleft() # 左邊出

【鏈表】

鏈表是一種動態的數據結構,在鏈表中添加虛擬頭節點,可以方便使用。鏈表的增刪改查操作複雜度都是O(n)。(如果在鏈表頭添加,修改和刪除,複雜度爲O(1))

  1. 添加元素 O(n)
  • 在鏈表頭添加元素(實現起來最簡單,無需遍歷鏈表):O(1)
  • 在鏈表中間添加元素:O(n)
  • 在鏈表末尾添加元素:O(n)
  1. 查找元素 O(n)
  • get(index),查詢鏈表index位置的節點:需要遍歷
  • get(elem),查找鏈表中是否含有elem節點:需要遍歷
  1. 修改元素,set(index),設置index位置的節點值。O(n)
  2. 刪除元素, 要找到待刪節點的前一個節點,修改其next指針。O(n)

鏈表實現棧

鏈表是動態數據結構,在鏈表頭添加,刪除和修改元素的複雜度爲O(1),
所以用鏈表實現棧的時候,將鏈表頭當作棧頂。

數組棧耗時的地方是:數組棧要時不時的resize數組容量,鏈表棧耗時的地方是:不停的創建node比較耗時。

帶有尾指針的鏈表實現隊列

帶有尾指針的鏈表,可以實現添加元素的複雜度降爲O(1).
head在鏈表頭,tail在鏈表尾,尾部複雜入隊,頭部負責出隊,這樣刪除和添加的複雜度都是O(1),可以實現隊列。

雙鏈表,循環鏈表,循環雙向鏈表,數組鏈表等

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章