和單向單端鏈表不同, 除了頭端,尾端也會維護一個指針(能夠加快在尾端添加節點的速度).
由於有着對最後一個鏈結點的直接引用.所以雙端鏈表比傳統鏈表在某些方面要方便.比如在尾部插入一個鏈結點.雙端鏈表可以進行直接操作
但傳統鏈表只能通過next節點循環找到最後鏈結點操作.所以雙端鏈表適合製造隊列(先進先出).
雙端鏈表可以插入表尾,但是仍然不能方便的刪除表尾,因爲我們沒有方法快捷地獲取倒數第二個鏈結點,雙端鏈表沒有逆向的指針,這一點就要靠雙向鏈表來解決了
實現參考:
class Node(object):
def __init__(self, value=None, next=None): # 這裏我們 root 節點默認都是 None,所以都給了默認值
self.value = value
self.next = next
def __str__(self):
"""方便你打出來調試,複雜的代碼可能需要斷點調試"""
return '<Node: value: {}, next={}>'.format(self.value, self.next)
__repr__ = __str__
class LinkedList(object):
""" 鏈接表 ADT
[root] -> [node0] -> [node1] -> [node2]
"""
def __init__(self, maxsize=None):
"""
:param maxsize: int or None, 如果是 None,無限擴充
"""
self.maxsize = maxsize
self.root = Node() # 默認 root 節點指向 None
self.tailnode = None
self.length = 0
def __len__(self):
return self.length
def append(self, value): # O(1)
if self.maxsize is not None and len(self) >= self.maxsize:
raise Exception('LinkedList is Full')
node = Node(value) # 構造節點
tailnode = self.tailnode
if tailnode is None: # 還沒有 append 過,length = 0, 追加到 root 後
self.root.next = node
else: # 否則追加到最後一個節點的後邊,並更新最後一個節點是 append 的節點
tailnode.next = node
self.tailnode = node
self.length += 1
def appendleft(self, value):
if self.maxsize is not None and len(self) >= self.maxsize:
raise Exception('LinkedList is Full')
node = Node(value)
if self.tailnode is None: # 如果原鏈表爲空,插入第一個元素需要設置 tailnode
self.tailnode = node
headnode = self.root.next
self.root.next = node
node.next = headnode
self.length += 1
def __iter__(self):
for node in self.iter_node():
yield node.value
def iter_node(self):
"""遍歷 從 head 節點到 tail 節點"""
curnode = self.root.next
while curnode is not self.tailnode: # 從第一個節點開始遍歷
yield curnode
curnode = curnode.next # 移動到下一個節點
if curnode is not None:
yield curnode
def remove(self, value): # O(n)
""" 刪除包含值的一個節點,將其前一個節點的 next 指向被查詢節點的下一個即可
:param value:
"""
prevnode = self.root #
for curnode in self.iter_node():
if curnode.value == value:
prevnode.next = curnode.next
if curnode is self.tailnode: # NOTE: 注意更新 tailnode
if prevnode is self.root:
self.tailnode = None
else:
self.tailnode = prevnode
del curnode
self.length -= 1
return 1 # 表明刪除成功
else:
prevnode = curnode
return -1 # 表明刪除失敗
def find(self, value): # O(n)
""" 查找一個節點,返回序號,從 0 開始
:param value:
"""
index = 0
for node in self.iter_node(): # 我們定義了 __iter__,這裏就可以用 for 遍歷它了
if node.value == value:
return index
index += 1
return -1 # 沒找到
def popleft(self): # O(1)
""" 刪除第一個鏈表節點
"""
if self.root.next is None:
raise Exception('pop from empty LinkedList')
headnode = self.root.next
self.root.next = headnode.next
self.length -= 1
value = headnode.value
if self.tailnode is headnode: # 勘誤:增加單節點刪除 tailnode 處理
self.tailnode = None
del headnode
return value
def clear(self):
for node in self.iter_node():
del node
self.root.next = None
self.length = 0
self.tailnode = None
def reverse(self):
"""反轉鏈表"""
curnode = self.root.next
self.tailnode = curnode # 記得更新 tailnode,多了這個屬性處理起來經常忘記
prevnode = None
while curnode:
nextnode = curnode.next
curnode.next = prevnode
if nextnode is None:
self.root.next = curnode
prevnode = curnode
curnode = nextnode
def test_linked_list():
ll = LinkedList()
ll.append(0)
ll.append(1)
ll.append(2)
ll.append(3)
print(ll)
assert len(ll) == 4
assert ll.find(2) == 2
assert ll.find(-1) == -1
assert ll.remove(0) == 1
assert ll.remove(10) == -1
assert ll.remove(2) == 1
assert len(ll) == 2
assert list(ll) == [1, 3]
assert ll.find(0) == -1
ll.appendleft(0)
assert list(ll) == [0, 1, 3]
assert len(ll) == 3
headvalue = ll.popleft()
assert headvalue == 0
assert len(ll) == 2
assert list(ll) == [1, 3]
assert ll.popleft() == 1
assert list(ll) == [3]
ll.popleft()
assert len(ll) == 0
assert ll.tailnode is None
ll.clear()
assert len(ll) == 0
assert list(ll) == []
def test_linked_list_remove():
ll = LinkedList()
ll.append(3)
ll.append(4)
ll.append(5)
ll.append(6)
ll.append(7)
ll.remove(7)
print(list(ll))
def test_single_node():
# https://github.com/PegasusWang/python_data_structures_and_algorithms/pull/21
ll = LinkedList()
ll.append(0)
ll.remove(0)
ll.appendleft(1)
assert list(ll) == [1]
def test_linked_list_reverse():
ll = LinkedList()
n = 10
for i in range(n):
ll.append(i)
ll.reverse()
assert list(ll) == list(reversed(range(n)))
def test_linked_list_append():
ll = LinkedList()
ll.appendleft(1)
ll.append(2)
assert list(ll) == [1, 2]
if __name__ == '__main__':
test_single_node()
test_linked_list()
test_linked_list_append()
test_linked_list_reverse()