線性表(六):雙向迴圈連結串列的基本操作
阿新 • • 發佈:2020-10-12
引言
本節將介紹最後一個連結串列的變形——雙向迴圈連結串列,這一結構在雙向連結串列的基礎上優化了對尾部節點的插入/刪除效率。
雙向迴圈連結串列
基本操作基本與雙向連結串列類似,但是要注意每個操作都要考慮到首尾節點的指標。
Python實現:
class DoublyListNode(): def __init__(self, val, prev_=None, next_=None): self.val = val self.next_ = next_ self.prev_ = prev_ class DoubleCircularLinkedList(): def __init__(self): self.rear = None self.head = None # 判斷連結串列是否為空 def is_empty(self): return self.rear is None # 向頭部插入元素 def prepend(self, element): p = DoublyListNode(element, None, self.head) if self.is_empty(): self.rear = p else: p.next_.prev_ = p self.head = p self.rear.next_ = self.head self.head.prev_ = self.rear # 向尾部插入元素 def append(self, element): p = DoublyListNode(element, self.rear, None) if self.is_empty(): self.head = p else: p.prev_.next_ = p self.rear = p self.rear.next_ = self.head self.head.prev_ = self.rear # 彈出頭部元素 def pop_first(self): if self.is_empty(): raise ValueError('連結串列為空,該操作無效!') output = self.head.val self.head = self.head.next_ if self.head: self.head.prev_ = self.rear self.rear.next_ = self.head return output # 彈出尾部元素 def pop_last(self): if self.is_empty(): raise ValueError('連結串列為空,該操作無效!') output = self.rear.val self.rear = self.rear.prev_ if self.rear: self.rear.next_ = self.head self.head.prev_ = self.rear return output # 獲取連結串列長度 def get_length(self): if self.is_empty(): return 0 cur = self.head length = 1 while cur.next_ != self.head: cur = cur.next_ length += 1 return length # 向指定位置插入任意元素 def insert(self, position, element): l = self.get_length() if position >= l or position < 0: raise IndexError('下標越界!') elif position == 0: self.prepend(element) elif position == l-1: self.append(element) else: if self.is_empty(): raise IndexError('下標越界!') if position <= l / 2: cur = self.head while position > 0: cur = cur.next_ position -= 1 p = DoublyListNode(element, None, cur) cur.prev_.next_ = p else: cur = self.rear while position < l-1: cur = cur.prev_ position += 1 p = DoublyListNode(element, None, cur) cur.prev_.next_ = p # 刪除指定元素 def remove(self, element): if self.is_empty(): raise IndexError('下標越界!') if self.head.val == element: self.head = self.head.next_ if self.head: self.head.prev_ = self.rear elif self.rear.val == element: self.rear = self.rear.prev_ if self.rear: self.rear.next_ = self.head else: cur = self.head flag = False while cur.val != element and cur.next_ != self.head: cur = cur.next_ if cur and cur.val == element: flag = True if flag: cur.prev_.next_ = cur.next_ else: raise ValueError('連結串列中不存在該元素!') if __name__ == '__main__': def testfunction(node): nums = [] cur = node while cur.next_ != node: nums.append(cur.val) cur = cur.next_ nums.append(cur.val) return nums sample = DoubleCircularLinkedList() for i in range(8): sample.prepend(i) print(testfunction(sample.head)) sample.append(2) print(testfunction(sample.head)) print(sample.get_length()) print(sample.pop_last()) print(testfunction(sample.head)) sample.insert(1, 10) print(testfunction(sample.head)) sample.remove(1) print(testfunction(sample.head))
總結
從但單鏈表到單向迴圈連結串列,通過新增尾部節點引用,提高了尾插法的效率,再到雙向連結串列實現了兩端高效插入,最後到雙向迴圈連結串列,彌補了雙向連結串列尾部元素插入低效的問題,這一系列改進操作似乎是強化了連結串列結構,但事實上如果非必要,我們還是優先考慮單鏈表,因為其他結構雖然操作上優化了不少,但同時也需要更多的空間去存放指標。此外,相比於順序表,雖然連結串列的儲存方式更加靈活,但連結串列定位查詢操作的複雜度較高,這也是這一結構最大的劣勢。