資料結構(二)雙向連結串列的的分析與python程式碼實現
阿新 • • 發佈:2019-01-11
概念
每個節點有兩個連結:一個指向前一個節點,當此節點為第一個節點時,指向空值;而另一個指向下一個節點,當此節點為最後一個節點時,指向空值。
特點:
節點包含三個域,一個元素域,兩個連結域(前驅和後繼),第0個節點沒有前驅,最後一個節點沒有後繼,在單鏈表的基礎上,增加向前指向的考慮。
結構
python程式碼實現
class Node(object): """實現雙向連結串列節點""" def __init__(self, item): # item存放資料元素 self.item = item # next代表後一個節點 self.next = None # prev代表前一個節點 self.prev = None class DoubleLinkList(object): """雙向連結串列""" def __init__(self): # 表示首節點 self.head = None # 連結串列是否為空 def is_empty(self): return self.head is None # 連結串列長度 def length(self): # cur初始時指向頭節點 cur = self.head n = 0 # 當未到達尾節點None時 while cur is not None: n += 1 # 將cur後移一個節點 cur =cur.next return n # 遍歷整個連結串列 def travel(self): cur = self.head while cur is not None: print(cur.item, end='-') cur = cur.next # 輸出連結串列 print() # 連結串列頭部新增元素 def add(self, item): # 呼叫Node類,例項node物件 node = Node(item) # 先讓新增加的節點next指向原首節點 node.next = self.head # 然後讓head指向新節點 self.head = node # 原首節點存在時,原首節點向前指向新節點,實現雙向 if node.next is not None: node.next.prev = node # 連結串列尾部新增元素 def append(self, item): # 若連結串列為空,則直接在頭部新增 if self.is_empty(): self.add(item) return # 1、連結串列不為空,需要遍歷查詢尾節點 cur = self.head while cur.next is not None: cur = cur.next # 至此cur指向當前連結串列的尾節點 # 2、讓cur的next指向新節點 node = Node(item) cur.next = node # 3、新節點向前指向cur node.prev = cur # 指定位置新增元素 def insert(self, pos, item): # 需要對新增的位置進行分類討論 # 如果新增位置<=0,則直接在頭部新增 if pos <= 0: self.add(item) # 位置大於連結串列長度,則直接新增到尾部 elif pos >= self.length(): self.append(item) else: # 1 遍歷查詢待插入位置的前一個節點cur cur = self.head for i in range(pos-1): cur = cur.next # 至此,cur指向的就是待插入位置的前一個節點 # 2 新節點的next指向cur的next node = Node(item) node.next = cur.next # 3 cur的next指向新節點 cur.next = node # 4 新節點的後繼節點向前指向新節點(雙向,向前) node.next.prev = node # 5 新節點向前指向cur(雙向,向前) node.prev = cur # 刪除節點 def remove(self, item): # 思路:讓待刪節點的pre(前節點)next指向待刪節點的next cur = self.head # 1 找到待刪節點並記錄前一個節點 while cur is not None: # 待刪節點不存在也就不用刪了,若存在 if cur.item == item: # 2 若cur有前驅節點則:cur的前驅節點指向cur的後繼節點,越過待刪節點 if cur.prev is not None: cur.prev.next = cur.next # 否則(待刪節點是第0個節點),head指向待刪節點的next else: self.head = cur.next # 3 若cur有後繼節點,則cur的後繼節點向前指向cur的前驅節點(越過待刪節點) if cur.next is not None: cur.next.prev = cur.prev return cur = cur.next # 查詢某個節點是否存在 def search(self, item): cur = self.head while cur is not None: if cur.item == item: return True cur = cur.next # 沒有找到 return False # 測試程式碼 if __name__ == '__main__': dl = DoubleLinkList() dl.add(1) dl.add(2) dl.add(3) dl.travel() # 結果3-2-1- dl.append("abc") dl.append("def") dl.append("ghi") dl.travel() # 結果3-2-1-abc-def-ghi- dl.insert(-1, "xx") dl.insert(99, "yy") dl.insert(3, "zz") dl.travel() # 結果xx-3-2-zz-1-abc-def-ghi-yy- dl.remove("xx") dl.remove("yy") dl.remove(1) dl.remove(90) dl.travel() # 結果3-2-zz-abc-def-ghi- print(dl.search(3)) # 結果True print(dl.search("zz")) # 結果True print(dl.search(380)) # 結果False
複雜度
頭部新增O(1),尾部新增O(n),指定位置新增O(n),
刪除節點:
若cur有前驅節點則:cur的前驅節點指向cur的後繼節點 O(n),否則:head指向cur的後繼節點 O(1)