集合中存儲的元素是有順序的。順序表的結構能夠分爲兩種形式:單數據類型和多數據類型。node
單數據類型:例如np.arraypython
單數據類型:內存連續開闢,在內存中存儲 int a = 10,20,30圖例以下數據結構
多數據類型:例如python中的listapp
多數據類型:內存非連續開闢,在內存中如何存儲 li = 10,'a',96.5,如何獲取每個數據值呢?測試
- 順序表的弊端:順序表的結構須要預先知道數據大小來申請連續的存儲空間,而在進行增長刪除時又須要進行數據的搬遷。spa
- Python中的 list 和 tuple 兩種類型採用了順序表的實現技術。3d
相對於順序表,鏈表結構能夠充分利用計算機內存空間,實現靈活的內存動態管理。指針
鏈表(Linked list)是一種常見的基礎數據結構,是一種線性表,可是不像順序表同樣連續存儲數據,而是每個結點(數據存儲單元)裏存放下一個結點的信息(即地址):code
單向鏈表也叫單鏈表,是表中最簡單的一種形式,它的每一個節點包含兩個域,一個信息域(元素域)和一個連接域。這個連接指向鏈表中的下一個節點,而最後一個節點的連接域則指向一個空值。對象
- 表中元素elem用來存放具體的數據。
- 連接域next用來存放下一個節點的位置。
- 變量p指向鏈表的頭節點(首節點)的位置,從p出發能找到表中的任意節點。
單向鏈表的抽象數據類型定義:
. is_empty():鏈表是否爲空
. length():鏈表長度
. travel():遍歷整個鏈表
. add(item):鏈表頭部添加元素
. append(item):鏈表尾部添加元素
. insert(pos, item):指定位置添加元素
. remove(item):刪除節點
. search(item):查找節點是否存在
# 第一步:建立節點(node) class Node(object): def __init__(self,item): # 存放新節點的值 self.item = item # 新節點沒有下一個連接地址 self.next = None # 建立連接 class Link(object): def __init__(self): # _head永遠指向的第一個節點的地址 self._head = None # 添加一個連接 def add(self,item): # 建立新節點 node = Node(item) # 將新節點的next地址指向 舊節點的_head指向 node.next = self._head # 新節點地址指向新節點內存空間地址 self._head = node # 獲取鏈表值 def travel(self): # 獲取第一個節點指針 cur = self._head # 判斷鏈表next指向爲空時,則爲鏈表的最後一個節點 while cur: # 打印節點item屬性值 print(cur.item) # 將新的節點指針賦值給cur變量 cur = cur.next def length(self): # 獲取第一個節點指針 cur = self._head # 長度計數器 count = 0 # 判斷鏈表next指向爲空時,則爲鏈表的最後一個節點 while cur: # 打印節點item屬性值 count += 1 # 將新的節點指針賦值給cur變量 cur = cur.next # 打印計數器 print("當前鏈表長度: ",count) return count # 判斷鏈表是否爲空 def isEmpty(self): # 判斷鏈表指針爲None時,鏈表爲空,返回True return self._head == None # 鏈表尾部追加元素 def append(self,item): node = Node(item) # 判斷鏈表是否爲空 if self.isEmpty(): # 鏈表爲空,添加新節點 self._head = node return # 鏈表不爲空,追加節點 cur = self._head # 定義一個變量,保存前一個節點的地址 pre = None # 判斷 while cur: pre = cur cur = cur.next # 最後next指針指向新加節點 pre.next = node # 查詢鏈表 查詢成功返回True,不然返回False def search(self,item): find = False cur = self._head while cur: # 查詢成功 if cur.item == item: find = True break else: # 鏈表指針指向下一個鏈表節點 cur = cur.next return find # 鏈表的插入操做 def insert(self,pos,item): # 查詢鏈表長度 length = self.length() if pos <=0 or pos >length: print("插入位置超出範圍!!!") return # pos添加的位置規定從1開始 node = Node(item) cur = self._head pre = None # 在位置1插入 if pos == 1: node.next = self._head self._head = node return # for循環,使鏈表指針指向pos插入位置 for i in range(1,pos): pre = cur cur = cur.next # 此時鏈表指針指向須要插入數據的位置 # 此時把pre指向的上一個指針地址指向插入節點的地址 pre.next = node # 把插入節點地址指針指向下一個節點地址 node.next = cur # 刪除指定位置節點 def remove(self,item): # 獲取第一個節點指針 cur = self._head pre = None # 此處沒有節點能夠刪除 if self._head == None: return # 刪除第一個節點 if cur.item == item: self._head = cur.next return # 刪除其餘位置節點 while cur: # 將新的節點指針賦值給下一個節點地址 if cur.item == item: pre.next = cur.next break else: pre = cur cur = cur.next
# 鏈表測試 # 實例化鏈表對象 link = Link() # 添加節點 link.add(1) link.add(2) link.add(3) # 顯示鏈表值 link.travel() # 刪除元素2 link.remove(2) link.travel() # 插入在鏈表位置1處插入一個節點6 link.insert(4,8) link.travel()
單鏈表的一個變形是單向循環鏈表,鏈表中最後一個節點的next域再也不爲None,而是指向鏈表的頭結點。
基本操做和單鏈表基本同樣,實現代碼以下:
# coding=utf-8 # 單向循環鏈表 class Node: """節點""" def __init__(self, item): self.item = item self.next = None def __str__(self): return str(self.item) class SinCycLinkedList: """單向循環鏈表""" def __init__(self): self._head = None def is_empty(self): """判斷鏈表是否爲空""" return self._head is None def length(self): """鏈表長度""" if self.is_empty(): return 0 count = 1 cur = self._head while cur.next != self._head: # print("cur", cur.item) count += 1 cur = cur.next return count def travel(self): """遍歷""" if self.is_empty(): return cur = self._head print(cur.item) while cur.next != self._head: cur = cur.next print(cur.item) def add(self, item): """在頭部添加一個節點""" node = Node(item) if self.is_empty(): self._head = node node.next = self._head else: node.next = self._head cur = self._head while cur.next != self._head: cur = cur.next cur.next = node self._head = node def append(self, item): """在尾部添加一個節點""" node = Node(item) if self.is_empty(): self._head = node node.next = self._head else: cur = self._head # print(type(cur), cur.item, cur.next) while cur.next != self._head: cur = cur.next # print(cur.item) cur.next = node node.next = self._head def insert(self, pos, item): """指定位置pos添加節點""" if pos <= 0: self.add(item) elif pos > (self.length() - 1): self.append(item) else: node = Node(item) cur = self._head cur_pos = 0 while cur.next != self._head: if (pos - 1) == cur_pos: node.next = cur.next cur.next = node break cur_pos += 1 cur = cur.next def remove(self, item): """刪除一個節點""" if self.is_empty(): return pre = self._head # 刪除首節點 if pre.item == item: cur = pre while cur.next != self._head: cur = cur.next cur.next = pre.next # 刪除首節點(跳過該節點) self._head = pre.next # 從新指定首節點 # 刪除其餘的節點 else: cur = pre while cur.next != self._head: if cur.next.item == item: cur.next = cur.next.next cur = cur.next def search(self, item): """查找節點是否存在""" if self.is_empty(): return -1 cur_pos = 0 cur = self._head if cur.item == item: return cur_pos while cur.next != self._head: if cur.item == item: return cur_pos cur_pos += 1 cur = cur.next if cur_pos == self.length() - 1: return -1 if __name__ == "__main__": ll = SinCycLinkedList() ll.add(1) # 1 ll.add(2) # 2 1 # ll.travel() ll.append(3) # 2 1 3 ll.insert(2, 4) # 2 1 4 3 ll.insert(4, 5) # 2 1 4 3 5 ll.insert(0, 6) # 6 2 1 4 3 5 print("length:", ll.length()) # 6 ll.travel() # 6 2 1 4 3 5 print("search(3)", ll.search(3)) # 4 print("search(7)", ll.search(7)) # -1 print("search(6)", ll.search(6)) # 0 print("remove(1)") ll.remove(1) print("length:", ll.length()) # 6 2 4 3 5 print("remove(6)") ll.remove(6) ll.travel()
一種更復雜的鏈表是 "雙向鏈表" 或 "雙面鏈表"。每一個節點有兩個連接:一個指向前一個節點,當次節點爲第一個節點時,指向空值;而另外一個指向下一個節點,當此節點爲最後一個節點時,指向空值。
代碼實現:
# coding=utf-8 # 雙向鏈表 class Node: """節點""" def __init__(self, item): self.item = item self.prev = None self.next = None class DLinkList: """雙向鏈表""" def __init__(self): self._head = None def is_empty(self): """判斷鏈表是否爲空""" return self._head is None def length(self): """獲取鏈表長度""" if self.is_empty(): return 0 else: cur = self._head count = 1 while cur.next is not None: count += 1 cur = cur.next return count def travel(self): """遍歷鏈表""" print("↓↓" * 10) if self.is_empty(): print("") else: cur = self._head print(cur.item) while cur.next is not None: cur = cur.next print(cur.item) print("↑↑" * 10) def add(self, item): """鏈表頭部添加節點""" node = Node(item) if self.is_empty(): self._head = node else: cur = self._head node.next = cur cur.prev = node self._head = node def append(self, item): """鏈表尾部添加節點""" node = Node(item) if self.is_empty(): self._head = node else: cur = self._head # 遍歷找到最後一個節點 while cur.next is not None: cur = cur.next # 在尾節點添加新的節點 cur.next = node node.prev = cur def insert(self, pos, item): """指定位置添加""" # 頭部添加 if pos <= 0: self.add(item) # 尾部添加 elif pos > (self.length() - 1): self.append(item) # 其餘位置添加 else: node = Node(item) cur = self._head cur_pos = 0 while cur.next is not None: if cur_pos == (pos - 1): # 與下一個節點互相指向 node.next = cur.next cur.next.prev = node # 與上一個節點互相指向 cur.next = node node.prev = cur cur_pos += 1 cur = cur.next def remove(self, item): """刪除節點""" if self.is_empty(): return else: cur = self._head # 刪除首節點 if cur.item == item: self._head = cur.next cur.next.prev = None # 刪除其餘節點 else: while cur.next is not None: if cur.item == item: # 刪除以前:1 ←→ [2] ←→ 3 # 刪除以後:1 ←→ 3 cur.prev.next = cur.next cur.next.prev = cur.prev cur = cur.next # 刪除尾節點 if cur.item == item: cur.prev.next = None def search(self, item): """查找節點是否存在""" if self.is_empty(): return -1 else: cur = self._head cur_pos = 0 while cur.next is not None: if cur.item == item: return cur_pos cur_pos += 1 cur = cur.next if cur_pos == (self.length() - 1): return -1 if __name__ == "__main__": ll = DLinkList() ll.add(1) # 1 ll.add(2) # 2 1 ll.append(3) # 2 1 3 ll.insert(2, 4) # 2 1 4 3 ll.insert(4, 5) # 2 1 4 3 5 ll.insert(0, 6) # 6 2 1 4 3 5 print("length:", ll.length()) # 6 ll.travel() # 6 2 1 4 3 5 print("search(3)", ll.search(3)) print("search(4)", ll.search(4)) print("search(10)", ll.search(10)) ll.remove(1) print("length:", ll.length()) ll.travel() print("刪除首節點 remove(6):") ll.remove(6) ll.travel() print("刪除尾節點 remove(5):") ll.remove(5) ll.travel()