Python資料結構-連結串列
1)概念:連結串列是一種物理儲存單元上非連續、非順序的儲存結構,資料元素的邏輯順序是通過連結串列中的指標連結次序實現的。連結串列由一系列結點(連結串列中每一個元素稱為結點)組成,結點可以在執行時動態生成。每個結點包括兩個部分:一個是儲存資料元素的資料域,另一個是儲存下一個結點地址的指標域。 相比於線性表順序結構,操作複雜。由於不必須按順序儲存,連結串列在插入的時候可以達到O(1)的複雜度,比另一種線性表順序錶快得多,但是查詢一個節點或者訪問特定編號的節點則需要O(n)的時間,而線性表和順序表相應的時間複雜度分別是O(logn)和O(1)。
使用連結串列結構可以克服陣列連結串列需要預先知道資料大小的缺點,連結串列結構可以充分利用計算機記憶體空間,實現靈活的記憶體動態管理。但是連結串列失去了
2)單向連結串列實現
class SingleNode:
"""節點類"""
def __init__(self,value,next=None):
self.value = value
self.next = next
def __repr__(self):
return '{}==>{}'.format(self.value,self.next.value if self.next else None)
class LinkedList:
def __init__(self):
self.head = None
self.tail = None
def append(self,value):
"""尾部追加"""
node = SingleNode(value) #頭尾是誰
#當前尾部
#當前的尾部的下一個指向新的node。
#當前尾部
tail = self.tail #第一個元素加進來,問self.tail尾部是誰。
if tail is None:
self.head = node
else:
tail.next = node
self.tail = node
return self
def iternodes(self):
current = self.head
while current:
yield current
current = current.next
ll = LinkedList()
ll.append('abd').append(1).append(3).append('def')
for i in ll.iternodes():
print(i)
思路:(1)首先要定義兩個類。節點類和容器類
(2)考慮到節點元素和節點元素的下一跳是誰。
(3)元素的容器內要考慮到頭部和尾部。
(4)定義append方法,尾部追加元素,當前節點等於第一個節點類追加元素。
(5)考慮到如果容器內沒有元素,那麼當前的頭部和尾部都為None,追加一個元素後,頭部不變,尾部就是當前的node。
(6)如果不為空,頭部不變,尾部為下一跳,最後當前的尾部為例項的尾部。
(7)定義迭代方法。利用生成器,每次取元素的當前節點,從頭開始,yield當前元素,下一跳元素,當前節點等下一跳的元素。
3)#雙向列表
class SingleNode:
"""節點類"""
def __init__(self,value,next=None,prev=None):
self.value = value
self.next = next
self.prev = prev
def __repr__(self):
return '{}<=={}==>{}'.format(
self.prev.value if self.prev else None,
self.value,
self.next.value if self.next else None)
class LinkedList:
"""容器類"""
def __init__(self):
self.head = None
self.tail = None
def append(self,value):
"""尾部追加"""
node = SingleNode(value) #頭尾是誰
#當前尾部
#當前的尾部的下一個指向新的node。
#當前尾部
tail = self.tail #第一個元素加進來,問self.tail尾部是誰。
if tail is None: #新增第一個元素
self.head = node
else:
tail.next = node
node.prev = tail #新增新元素進來,此時尾部還未指向新節點node,當前尾部還是上一個node的尾部。
# 所以新節點的上一跳為當前的尾部。
self.tail = node
return self
def pop(self):
"""尾部彈出"""
#empty
if self.tail is None:
raise Exception('empty')
#just one
# if self.head.next is None:
# if self.tail.prev is None:
#node = self.tail
oldtail = self.tail #等價於上面
if self.head is self.tail: #just one current
self.head = None
self.tail = None
else:
# node.prev = None
# node.prev.next = None
# self.tail = node.prev #更新尾部
prev = oldtail.prev
prev.next = None
self.tail = prev #等價於上面的
oldtail.prev = None
return oldtail
def insert(self,index,value):
if index < 0:
raise IndexError('Wrong index{}'.format(index))
current = None
for i,node in enumerate(self.iternodes()):
if index == i:
current = node
break
else:
#超過當前迭代。index>length -1
self.append(value) #空連結串列直接尾部追加,然後返回了
return
#找到內部的插入點,非空的
#至少node一定有,不能是node
prev = current.prev
#next = current.next
node = SingleNode(value)
if index == 0:
node.next = current
current.prev = node
self.head = node
else:
prev.next = node
node.next = current
current.prev = node
node.prev = prev
def remove(self,index):
#很多元素
#兩個元素
#1個元素
#0個元素
if index < 0:
raise IndexError('Wrong index{}'.format(index))
if self.tail is None: #0個元素
raise Exception('empty')
if self.head is self.tail: #一個元素
node = self.head
self.head = None
self.tail = None
del node
return 0
current = None
for i, node in enumerate(self.iternodes()):
if index == i:
current = node
break
# else:
# raise IndexError('out of boundary')
else:
# 超過當前迭代。index>length -1
self.pop() # 空連結串列直接尾部追加,然後返回了
return
prev = current.prev
next = current.next
if index == 0:
next.prev = None
self.head = next
#tail 處理
elif next is None: #移除尾部
prev.next = None
self.tail = prev
else:#mid處理
prev.next = next
next.prev = prev
del current
return index
# def iternodes(self):
# current = self.head
# while current:
# yield current
# current = current.next
def iternodes(self,reverse = False):
current = self.tail if reverse else self.head
while current:
yield current
current = current.prev if reverse else current.next
ll = LinkedList()
ll.append('abd').append(1).append(3).append('def')
for i in ll.iternodes():
print(i)
print('+++++++')
print(ll.pop())
print(ll.pop())
ll.insert(1000,'acd')
ll.insert(3,3)
print('-----------------')
for i in ll.iternodes(True):
print(i)
ll.remove(1000)
for i in ll.iternodes():
print(i)
思路:(1)在單向連結串列的基礎上改進雙向連結串列。因為是雙向的所喲增加上一跳。
(2)定義pop方法,尾部彈出,考慮到連結串列裡面只有一個元素,為空和不為空的三種情況。一、如果為空的話,直接丟擲異常。二、一個元素的話,頭部和尾部全部為空。三、定義舊的尾部為原來的尾部,上一跳為原來尾部的上一跳,上一跳的下一跳變為None,新的尾部為原來node的上一跳,舊的尾部的上一跳為空,返回舊尾部。
(3)Insert方法(需要索引index和值),一、首先不支援副索引,如果輸入的索引為負數的,直接丟擲異常。二、索引超屆的的直接尾部追加。三、利用for迴圈來迭代連結串列,索引對應迭代序號,如果索引為0的情況下,對應的元素上一跳為新元素,當前元素的下一跳為對應的元素node。如果在中間插入的話,需要有四種改變,前面元素的下一跳為當前要插入的元素,後面的元素上一跳為當前這個元素。當前元素前元素的前一跳還是前一跳,前面元素的下一跳是當前元素。
else:
prev.next = node
node.next = current
current.prev = node
node.prev = prev
(4)remove要考慮四種情況:有很多元素,有兩個元素,有一個元素,有0個元素。一、支援副索引。二、0個元素的話,直接丟擲異常屬性。三、一個元素的話,頭部尾部全部為空。
4)改變成為容器;
class SingleNode:
def __init__(self,value,next = None,prev = None):
self.value = value
self.next = next
self.prev = prev
def __repr__(self):
return "{}<=={}==>{}".format(
self.prev.value if self.prev else None,
self.value,
self.next.value if self.next else None)
class LinkList:
def __init__(self):
self.head = None
self.tail = None
self.items = []
def append(self,value):
node = SingleNode(value)
tail = self.tail
if tail is None:
# self.tail = node
self.head = node
else:
tail.next = node
node.prev = tail
self.tail = node
self.items.append(node)
return self
def pop(self):
if self.tail is None: #empty
raise Exception('empty')
oldtail = self.tail
if self.head is self.tail:
self.tail = None
self.head = None
else:
prev = oldtail.prev
prev.next = None
self.tail = prev
oldtail.prev = None
self.items.pop()
return oldtail
def insert(self,index,value,):
if index < 0:
raise IndexError('wrong index{}'.format(index))
current = None
for i,conde in enumerate(self.iternodes()):
if index == i:
current = conde
break
else: ###超過當前迭代。
self.append(value)
# self.items.append(value)
return
#找到內部插入點
prev = current.prev
next = current.next
node = SingleNode(value)
if index == 0: #在頭部插入
node.next = current
current.prev = node
self.head = node
else:
current.prev = node
node.next = current
prev.next = node
node.prev = prev
self.items.insert(index,node)
def remove(self,index):
if index < 0 :
raise IndexError('Wrong index{}'.format(index))
if self.tail is None: #0個元素
raise Exception('empty')
if self.head is self.tail:#一個元素
node = self.head
self.head = None
self.tail = None
del node
self.items.pop()
return 0
current = None
for i,node in enumerate(self.iternodes()):
if index == i:
current = node
break
else:
self.pop()
self.items.pop()
return
prev = current.prev
next = current.next
if index == 0:
next.prev = None
self.head = next
else: #中間的處理
prev.next = next
next.prev = prev
del current
self.items.pop(index)
return index
# def iternodes(self):
# current = self.head
# while current:
# yield current
# current = current.next
#
def iternodes(self,revese=False):
current = self.head
while current:
yield current
current =self.tail if revese else current.next
思路:改變容器化就是利用技巧和原來的保持一致就行了。
(1)容器裡面設定一個屬性self.items = []初始化一個列表。
(2)Append方法裡面和原來的方法一致,self.items.append(node)
(3)Pop方法裡面和原方法一樣,也是尾部增加一個self.items.pop()尾部彈出一個元素。
(4)insert方法裡面,超出索引的話,直接尾部增加元素,採用self.items.append(value).找到尾部插入點:self.items.insert(index,node)
(5)remove方法,如果是一個元素的話,也是採用尾部彈出的方法,self.items.pop().多個元素的話直接就是self.items.pop(index)
1)使用getitem查詢元素
class SingleNode:
def __init__(self,value,next = None,prev = None):
self.value = value
self.next = next
self.prev = prev
def __repr__(self):
return "{}<=={}==>{}".format(
self.prev.value if self.prev else None,
self.value,
self.next.value if self.next else None)
class LinkList:
def __init__(self):
self.head = None
self.tail = None
self.items = []
def append(self,value):
node = SingleNode(value)
tail = self.tail
if tail is None:
# self.tail = node
self.head = node
else:
tail.next = node
node.prev = tail
self.tail = node
self.items.append(node)
return self
def pop(self):
if self.tail is None: #empty
raise Exception('empty')
oldtail = self.tail
if self.head is self.tail:
self.tail = None
self.head = None
else:
prev = oldtail.prev
prev.next = None
self.tail = prev
oldtail.prev = None
self.items.pop()
return oldtail
def insert(self,index,value,):
if index < 0:
raise IndexError('wrong index{}'.format(index))
current = None
for i,conde in enumerate(self.iternodes()):
if index == i:
current = conde
break
else: ###超過當前迭代。
self.append(value)
# self.items.append(value)
return
#找到內部插入點
prev = current.prev
next = current.next
node = SingleNode(value)
if index == 0: #在頭部插入
node.next = current
current.prev = node
self.head = node
else:
current.prev = node
node.next = current
prev.next = node
node.prev = prev
self.items.insert(index,node)
def remove(self,index):
if index < 0 :
raise IndexError('Wrong index{}'.format(index))
if self.tail is None: #0個元素
raise Exception('empty')
if self.head is self.tail:#一個元素
node = self.head
self.head = None
self.tail = None
del node
self.items.pop()
return 0
current = None
for i,node in enumerate(self.iternodes()):
if index == i:
current = node
break
else:
self.pop()
self.items.pop()
return
prev = current.prev
next = current.next
if index == 0:
next.prev = None
self.head = next
else: #中間的處理
prev.next = next
next.prev = prev
del current
self.items.pop(index)
return index
# def iternodes(self):
# current = self.head
# while current:
# yield current
# current = current.next
#
def iternodes(self,revese=False):
current = self.head
while current:
yield current
current =self.tail if revese else current.next
# def __len__(self):
# return len()
#
# def __setitem__(self, key, value):
# self.items[key] = value
#
# def __getitem__(self, index):
# return self.items[index]
def getitem(self,index):
if index < 0:
raise Exception('wrong index{}'.format(index))
current = None
for i,node in enumerate(self.iternodes()):
if i == index:
return self.items[index]
else:
return self.items[-1]
ll = LinkList()
ll.append(2).append(3).append(4).append(5)
for i in ll.iternodes():
print(i)
print('-------------')
ll.pop()
ll.pop()
for i in ll.iternodes():
print(i)
ll.insert(5,5)
ll.insert(100,100)
for i in ll.iternodes():
print(i)
print('++++++++++')
ll.remove(1)
for i in ll.iternodes():
print(i)