python資料結構之連結串列(linked list)
目錄
- 基礎 知識
1.1 連結串列的基本結構
1.2 節點類和連結串列節點的定義
1.3 順序列印和逆序列印 - 連結串列的基本操作
2.1 計算連結串列長度
2.2 從前,後插入資料
2.3 查詢與刪除
參考
1.基礎 知識
1.1 連結串列的基本結構
連結串列是通過一個個節點組成的,每個節點都包含了稱為cargo的基本單元,它也是一種遞迴的資料結構。它能保持資料之間的邏輯順序,但儲存空間不必按照順序儲存。
如圖:
連結串列的基本元素有:
- 節點:每個節點有兩個部分,左邊部分稱為值域,用來存放使用者資料;右邊部分稱為指標域,用來存放指向下一個元素的指標。
- head:head節點永遠指向第一個節點
- tail: tail永遠指向最後一個節點
- None:連結串列中最後一個節點的指標域為None值
但連結串列也分為單向連結串列和單向迴圈連結串列,雙向連結串列和雙向迴圈連結串列,如圖為單向連結串列和單向迴圈連結串列:
寫個基本程式測試一下:
1.2 節點類和連結串列節點的定義
節點類定義如下:
class Node:
def __init__(self,cargo = None, next = None):
self.cargo = cargo
self.next = next
def __str__(self):
#測試基本功能,輸出字串
return str(self.cargo)
print Node("text")
#輸出text
因為任何值都能通過str函式,且能儲存下來。
連結串列怎麼定義呢?
我們可以先定義一個一個節點,如下:
node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
然後再把每個節點的關係表示出來,就OK了
node1.next = node2
node2.next = node3
1.3 順序列印和逆序列印
因為先前已經建立了關係,所以可以通過輸入第一個節點,迴圈整個連結串列然後順序列印整個連結串列。
def printList(node):
while node:
print node
node = node.next
printList(node1)
1
2
3
使用遞迴的方法來列印,主要步驟如下:
- 將list拆分成兩個部分,head:第一個元素,tail:其餘元素
- 向後列印
- 列印第一個元素
def printBackward(lists):
if lists == None:
return
head = lists
tail= lists.next
print head,tail
printBackward(tail)
print head,tail
printBackward(node1)
1 2
2 3
3 None
3 None
2 3
1 2
事實上,還能更簡便。
def printBackward(lists):
if lists == None:return
printBackward(lists.next)
print lists
printBackward(node1)
2.連結串列的基本操作
在連結串列的基本操作中,包括插入,刪除等,但要注意的是一下的操作是針對非迴圈連結串列的,從頭節點開始操作,而且我們不能插入 None值到連結串列中。
2.1 計算連結串列長度
class Node(object):
#節點類
#功能:輸入一個值data,將值變為一個節點
def __init__(self, data, next = None):
self.data = data
self.next = next
def __str__(self):
return self.data
class LinkedList(object):
def __init__(self, head = None):
self.head = head
def __len__(self):
#功能:輸入頭節點,返回連結串列長度
curr = self.head
counter = 0
while curr is not None:
counter += 1
curr = curr.next
return counter
2.2 從前,後插入
從前插入:
- 被插入資料為空,返回
- 使用該輸入資料建立一個節點,並將該節點指向原來頭節點
- 設定該節點為頭節點
時間複雜度和空間複雜度均為O(1)
def insertToFront(self,data):
#功能:輸入data,插入到頭節點前,並更改為頭節點
#輸出:當前頭節點
if data is None:
return None
node = Node(data,self.head)
self.head = node
return node
從後:append
- 若輸入資料為空,返回None
- 若頭節點為空,直接將輸入資料作為頭節點
- 遍歷整個連結串列,直到當前節點的下一個節點為None時,將當前節點的下一個節點設定為輸入資料
時間複雜度為O(n),空間O(1)
def append(self,data):
#功能:輸入data,作為節點插入到末尾
if data is None:
return None
node = Node(data)
if self.head is None:
self.head = node
return node
curr_node = self.head
while curr_node.next is not None:
curr_node = curr_node.next
curr_node.next = node
return node
2.3 查詢與刪除
查詢
- 若查詢的資料為空,返回
- 設定頭節點為當前節點,若當前節點不為None,遍歷整個連結串列
- 若當前節點的data與輸入的data相同,但會當前節點,否則輪到下一個節點
可見時間複雜度為O(n),空間複雜度為O(1).
def find(self,data):
#功能:查詢連結串列的節點data與data相同的節點
if data is None:
return None
curr_node = self.head
while curr_node is not None:
if curr_node.data == data:
return curr_node
curr_node = curr_node.next
return None
刪除1
申請兩個變數,如果遇到匹配的,不用刪除,直接將匹配節點的前一節點指向匹配節點的下一節點,因此需要定義一個前節點和一個當前節點,當前節點用來判斷是否與輸入資料匹配,前節點用來更改連結串列的指向。
- 若輸入資料為None,返回
- 將頭節點設定為前節點,頭節點的下一個節點設定為當前節點
- 判斷前節點是否與輸入資料匹配,若匹配,將頭節點設定為當前節點
- 遍歷整個連結串列,若當前節點與輸入資料匹配,將前節點的指標指向當前節點的下一個節點,否則,移到下一個節點
時間複雜度為O(n),空間複雜度為O(1).
def delete(slef,data):
#刪除節點
if data is None:
return None
if self.head is None:
return None
if self.head.data == data:
self.head = self.head.next
return
prev_node = self.head
curr_node = self.head.next
while curr_node is not None:
if curr_node.data == data:
prev_node.next = curr_node.next
else:
prev_node = curr_node
curr_node = curr_node.next
刪除2
第二種解決辦法就是隻定義一個變數作為當前節點,使用它的下一個節點去判斷是否與資料資料匹配,若匹配,直接將當前節點指向下下一個節點。
時間複雜度為O(n),空間複雜度為O(1).
def deleteAlt(self):
#只定義一個變數來完成刪除操作
if data is None:
return
if self.head is None:
return
if self.head.data == data:
self.head = self.head.next
return
curr_node = self.head
while curr_node.next is not None:
if curr_node.next.data == data:
curr_node.next = curr_node.next.next
return
curr_node = curr_node.next
reference