Link Lists
定義
由一組節點 (Node)
所組成的有序串列
,各 Node 除了 Data 欄
之外,另外有 ≥ 1 個 Link 欄
(或稱 Pointer),用以指向其它 Node 之位址。
特質
- 各Node不一定要佔用連續的Memory空間
- 各Node之型態 (Data Type) (Data Type) 不一定要相同
- 僅支援Sequential Access
- Insert/Delete Node Insert/Delete Node 容易
Link list的種類
Single Link List (單向鏈結串列)
由一組節點 (Node)
所組成的有序串列
,各 Node 除了 Data 欄之外,另外有 1 個Link欄
(或稱 Pointer),用以指向下一個 Node 之位址。
Create List
Insert Node
-
begin New(t); //跟系統要求記憶體空間以配置一個新節點,且讓指標 t 指向該節點 t → data = item; //把item塞到這個新節點t的Data欄位中 1 t → link = x → link;//先把新節點t掛到x節點之後!! 2 x → link = t; //再將x節點接到節點t end
-
begin New(t); t → data = x → data; t → link = x → link; x → link = t; x → data = 20; x = t; end;
Delete Node
刪除鏈節串列的節點時,會先:
- 改變串列指標,以做到
邏輯性移除
(Logically Remove)的動作 - 再將要被移除的節點做
實際刪除
(Physically Delete) 的動作,讓節點從記憶體中刪除
需要準備兩個輔助指標 x 與 pPre:
- x用以指向
欲刪除的節點
- pPre指向
節點x所在之前一個node
1 if (pPre = nil) then //表示 x 為第一個節點
list = x → link;
else //表示 x 節點是中間節點
pPre → link = x → link;
2 Ret(x); //將 “節點 x” 回收. 有的書是用delete(x), release(x), dispose(x)…etc.
Storage Pool
可用節點 (Free Node)
之集合 (集中管理之處),通常O.S.以 Single link list
來管理 Free Nodes,稱為 AV-list
(Available list) 提供兩個動作:
New(t)
: 相當於刪除 AV-list 中 Free Node (if AV-list ≠ nil)Ret(t)
: 相當於 Insert 節點到 AV-list 中
New(t)
if (AV ≠ nil) then
1 t = AV
2 AV = AV → link;
else
print(“No Free Node.”);
Ret(t)
begin
1 t → link = AV;
2 AV = t;
end
Circular Link List (環状鏈結串列)
將 Single link list 中,最後一個 node 的指標指回第一個 node
- 不論從哪個 Node 開始,必定能夠拜訪 (經過) 所有 Node
- 並無明顯的頭尾節點
- Single Link List 必須從頭開始才可以
- 回收整個串列的時間為
O(1)
(即: 與 Link list 長度無關)- Single Link List 回收時間為 O(n) 其中, n 為長度或 Node 數目
回收時間的比較(單向 vs. 環狀)
Single Linked List
Procedure Release list(list: pointer to S.L.)
if (list≠nil) then
S = list;
1 while (S → link ≠ nil) do //while迴圈會讓S一直前進至最後一節點
S = S → link;
2 S → link = AV;
3 AV = list; //回收節點至AV list AV list 中
Time Complexity: O(N)
Circular Linked List
Procedure Release C(C: pointer to S.L.)
begin
if (C≠nil) then
1 p = C → link;
2 C → link = AV;
3 AV = P
end
Time Complexity: O(1)
Double Link List (雙向鏈結串列)
串列中各節點除了 Data 欄之外,另外有 2 個 Link 欄,用以指向前一個與下一個節點之位址
一般使用雙向鏈結串列時,通常會加入串列首 (Head Node),此 Node 不存資料
此時,雙向鏈結串列可視為2個 Circular Link List
Insertion
插入Node t 在Node x之後:
begin
1 t → RLink = x → RLink;
2 t → LLink = x;
3 (x → RLink) → LLink = t;
4 x → RLink = t;
end
Deletion
刪除一個節點 x:
begin
1 (x → LLink) → RLink = x → RLink;
2 (x → RLink) → LLink = x → LLink ;
3 Ret(x);
end
Double linked list 與 Single linked list 的比較
Link list 三個常見的動作
Length
Single linked list
Procedure Length list(list: pointer to S.L.)
count = 0;
p = list;
while (p≠ nil) do
count++;
p = p → link;
return count;
Time Complexity: O(N)
Circular linked list
Procedure Length C(C: pointer to S.L.)
if (C = nil) then
return 0;
else
count = 0;
p = C;
repeat //不能用while迴圈!!∵一定至少要做一次!!!
count++;
p = p → link;
until p = C;
Time Complexity: O(N)
Concatenate
Single linked list
假設連結A, B串列成為C串列:
- Case 1: A = nil and B ≠ nil, 則 C = B
- Case 2: A ≠ nil and B = nil, 則 C = A
- Case 3: A ≠ nil and B ≠ nil, 則
C = A+B
- Case 4: A = nil and B = nil, 則 C = nil
Procedure Con.two.S(A, B, C: pointer to S.L.)
C = nil;
if (A = nil and B ≠ nil) then C = B; //Case 1
elif (A ≠ nil and B = nil) then C = A; //Case 2
elif (A ≠ nil and B ≠ nil) then //Case 3
p = A;
1 while(p → link ≠ nil) do
p = p → link;
2 p → link = B;
3 C = A;
return C; //回傳Case 1~4
Time Complexity: O(N) 或 O(M)
Circular linked list
假設連結A, B串列成為C串列:
- Case 1: A = nil and B ≠ nil, 則 C = B
- Case 2: A ≠ nil and B = nil, 則 C = A
- Case 3: A ≠ nil and B ≠ nil, 則
C = A+B
- Case 4: A = nil and B = nil, 則 C = nil
Procedure Con.two.S(A, B, C: pointer to C.L.)
C = nil;
if (A = nil and B ≠ nil) then C = B; //Case 1
elif (A ≠ nil and B = nil) then C = A; //Case 2
elif (A ≠ nil and B ≠ nil) then //Case 3
1 C = A → link;
2 A → link = B → link;
3 B → link = C;
return C; //回傳 Case 1~ 4 的結果
Time Complexity: O(1)
Invert ( Reverse )
Single linked list
需要三個指標: r, q, p
- r 跟著 q 走, q 跟著 p 走, p 往前進
Procedure Invert S(S: pointer to S.L.)
p = S; q = nil;
while (p ≠ nil) do
r = q; //r 一開始會在此被設為 nil
q = p;
p = p → link;
q → link = r;
S = q; //S可能指向反轉後的第一個節點或是null list
Procedure Invert S(S: pointer to S.L.)
p = S; q = nil;
while (p ≠ nil) do
r = q; //r 一開始會在此被設為 nil
q = p;
p = p → link;
q → link = r;
S = q; //S可能指向反轉後的第一個節點或是null list
PYTHON - Iterative
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
prev = None
while head:
curr = head
head = head.next
curr.next = prev
prev = curr
return prev
# python 簡潔寫法
# cur, prev = head, None
# while cur:
# cur.next, prev, cur = prev, cur, cur.next
# return prev
Time Complexity: O(N)
Recursive
### Circular linked list 亦需要三個指標: r, q, pclass Solution: # @param {ListNode} head # @return {ListNode} def reverseList(self, head): return self._reverse(head) def _reverse(self, node, prev=None): if not node: return prev n = node.next node.next = prev return self._reverse(n, node)
r跟著q走,q跟著p走,p往前進
Procedure Invert C(C: pointer to C.L.)
if (C ≠ nil) then
p = C → link; //p指向C的下一個node
q = C; //初值
while (p ≠ c) do
r = q;
q = p;
p = p → link;
q → link = r;
C → link = q;
C = q;
Time Complexity: O(N)