雙向鏈表的知識點很多都和單向鏈表相同,函數實現方法也差不多,只是需要注意每個節點的prev需要指向上一個節點。
雙向鏈表的節點實現:
'''雙向鏈表'''
# 節點實現
class Node(object):
def __init__(self, item):
self.item = item
# 前後指向地址暫定爲None
self.prev = None
self.next = None
需要注意的就是地址指向有兩個prev和next,初始值都設爲None
雙向鏈表實現:
# 雙向鏈表實現
class DoubleLinkList(object):
def __init__(self, node=None):
self.__head = node
因爲雙向鏈表中的首地址指向None,所以__init__函數中參量默認爲node=None,假如傳入參數node,不是空鏈表了,此時self.__head指向node。
雙向鏈表的增刪改查等函數實現:
1、判空函數:
def is_empty(self):
if self.__head == None:
return True
else:
return False
2、鏈表長度函數:
# 鏈表長度
def length(self):
# 考慮空鏈表情況
if self.is_empty():
return 0
# cur遊標 指向首節點,用來遍歷 相當於指針
cur = self.__head # 遊標指向首地址
count = 0 # 注意此時的初始值和非空情況的判斷條件的關係
# 非空情況下
while cur != None: # 初始值爲0 的判斷條件
count += 1
cur = cur.next
return count
# 另一種判空情況
# while cur.next != None: # 找到尾節點
# count += 1
# cur = cur.next # 繼續循環
# return count
這裏注意的是while虛表還條件的選擇,這個與count的初始值設定有關,還關乎尾節點是否在循環內的情況。
代碼中註釋掉的一部分代碼,就是另外一種的while循環條件,相對應的count=1,此時尾節點的數據沒有進入到循環內,需要單獨考慮。
3、遍歷鏈表
# 遍歷鏈表
def travel(self):
cur = self.__head
# 考慮空鏈表情況
if self.is_empty():
return None
# 非空鏈表的情況下:
while cur != None:
print(cur.item, end=' ')
cur = cur.next # 因爲判空條件的不同,尾節點已經在循環中
# while cur.next != None:
# print(cur.item)
# cur = cur.next
#
# print(cur.next) # 輸出結尾結點
和上面的函數實現相同,while循環條件的選擇,和輸出語句相關,註釋掉的代碼是另一種實現函數的方法。
4、鏈表頭部插入元素
def add(self, item):
node = Node(item)
# 空鏈表
if self.is_empty():
self.__head = node
else:
# 非空鏈表
# 第一步:將新的節點的地址指向初始鏈表的第一個元素
node.next = self.__head
# 第二步:將__head的頭節點的prev指向node
# cur.prev = node
self.__head.prev = node
# 第三步:將__head指向node
# node.prev = None
self.__head = node
這裏需要注意的是:註釋掉的代碼是一種錯誤的思路,需要區分開。註釋掉的代碼是沒有明確cur,prev和next代表的含義是什麼,這些都是指向節點的數據地址的“指針”。如下圖所示:
圖中箭頭代表的是指向的地址,代碼編寫的順序應該是從右往左編寫代碼,否則會出現地址指向錯誤,順序很重要!!!
5、鏈表尾部插入數據
# 尾部插入新節點
def append(self, item):
node = Node(item)
# 空鏈表
if self.is_empty():
self.__head = node
else:
# 非空鏈表
cur = self.__head
while cur.next != None: # 這裏不同於之前的臨界條件
# 找到最後一個節點
cur = cur.next
# 循環結束之後,cur指向尾部結點
cur.next = node
node.prev = cur
這裏的while循環條件特殊一點:因爲是在尾部插入,找到的節點需要是最後一個節點,節點的next爲None。
圖中箭頭代表的是指向的地址,代碼編寫的順序應該是從右往左編寫代碼,否則會出現地址指向錯誤,順序很重要!!!
6、鏈表任意位置插值
# 任意位置插值
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
count = 0
# 在鏈表長度內循環
while count < (pos - 1):
count += 1
cur = cur.next
# 循環結束
# 插入的節點next指向遊標所指的下一個節點
node.next = cur.next
# 新節點的prev指向遊標所指的節點
node.prev = cur
# 遊標所指下一個節點的prev指向新結點
cur.next.prev = node
# 遊標所在的節點的next指向新節點
cur.next = node
示意圖如下:
圖中箭頭代表的是指向的地址,代碼編寫的順序應該是從右往左編寫代碼,這裏最主要的是兩個指向需要先寫:1、插入的節點next指向遊標所指的下一個節點;2、新節點的prev指向遊標所指的節點;這兩個順序需要在(遊標所指下一個節點的prev指向新結點)(遊標所在的節點的next指向新節點)之前
7、查找節點是否存在
# 查找結點是否存在
def search(self, item):
cur = self.__head
# 循環查找
while cur != None:
if cur.item == item:
return True
else:
# 遊標繼續執行
cur = cur.next
return False
8、刪除鏈表節點
# 刪除鏈表節點
def remove(self, item):
if self.is_empty():
return None
else:
cur = self.__head
# 首結點的元素就是要刪除的元素
if cur.item == item:
# 如果鏈表只有一個結點
if cur.next == None:
self.__head = None # 首地址指向None
else: # 鏈表中不止一個節點數據
cur.next.prev = None # 下一個節點的prev指向None
self.__head = cur.next # 首地址只想下個節點
return None
while cur != None: # 循環到尾部節點數據之前
if cur.item == item: # 循環過程中找到需要的數據
cur.prev.next = cur.next # 當前要刪除節點的prev,即上一個節點,上一個節點的next指向刪除後的節點
if cur.next: # 如果刪除節點的下一個節點不是尾部節點
cur.next.prev = cur.prev # 下一個節點的prev指向刪除節點的前一個節點
break # 跳出循環
cur = cur.next # 繼續循環
示意圖如下:
代碼整體的實現:
# -*- encoding: utf-8 -*-
"""
@File : double_link_list.py
@Time : 2019/11/13 15:03
@Author : chen
"""
'''雙向鏈表'''
# 節點實現
class Node(object):
def __init__(self, item):
self.item = item
# 前後指向地址暫定爲None
self.prev = None
self.next = None
# 雙向鏈表實現
class DoubleLinkList(object):
def __init__(self, node=None):
self.__head = node #
def is_empty(self):
if self.__head == None:
return True
else:
return False
# 鏈表長度
def length(self):
# 考慮空鏈表情況
if self.is_empty():
return 0
# cur遊標 指向首節點,用來遍歷 相當於指針
cur = self.__head # 遊標指向首地址
count = 0 # 注意此時的初始值和非空情況的判斷條件的關係
# 非空情況下
while cur != None: # 初始值爲0 的判斷條件
count += 1
cur = cur.next
return count
# 另一種判空情況
# while cur.next != None: # 找到尾節點
# count += 1
# cur = cur.next # 繼續循環
# return count
# 遍歷鏈表
def travel(self):
cur = self.__head
# 考慮空鏈表情況
if self.is_empty():
return None
# 非空鏈表的情況下:
while cur != None:
print(cur.item, end=' ')
cur = cur.next # 因爲判空條件的不同,尾節點已經在循環中
# while cur.next != None:
# print(cur.item)
# cur = cur.next
#
# print(cur.next) # 輸出結尾結點
# 頭部插入元素
def add(self, item):
node = Node(item)
# 空鏈表
if self.is_empty():
self.__head = node
else:
# 非空鏈表
# 第一步:將新的節點的地址指向初始鏈表的第一個元素
node.next = self.__head
# 第二步:將__head的頭節點的prev指向node
# cur.prev = node
self.__head.prev = node
# 第三步:將__head指向node
# node.prev = None
self.__head = node
# 尾部插入新節點
def append(self, item):
node = Node(item)
# 空鏈表
if self.is_empty():
self.__head = node
else:
# 非空鏈表
cur = self.__head
while cur.next != None: # 這裏不同於之前的臨界條件
# 找到最後一個節點
cur = cur.next
# 循環結束之後,cur指向尾部結點
cur.next = node
node.prev = cur
# 任意位置插值
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
count = 0
# 在鏈表長度內循環
while count < (pos - 1):
count += 1
cur = cur.next
# 循環結束
# 插入的節點next指向遊標所指的下一個節點
node.next = cur.next
# 新節點的prev指向遊標所指的節點
node.prev = cur
# 遊標所指下一個節點的prev指向新結點
cur.next.prev = node
# 遊標所在的節點的next指向新節點
cur.next = node
# 查找結點是否存在
def search(self, item):
cur = self.__head
# 循環查找
while cur != None:
if cur.item == item:
return True
else:
# 遊標繼續執行
cur = cur.next
return False
# 刪除鏈表節點
def remove(self, item):
if self.is_empty():
return None
else:
cur = self.__head
# 首結點的元素就是要刪除的元素
if cur.item == item:
# 如果鏈表只有一個結點
if cur.next == None:
self.__head = None # 首地址指向None
else: # 鏈表中不止一個節點數據
cur.next.prev = None # 下一個節點的prev指向None
self.__head = cur.next # 首地址只想下個節點
return None
while cur != None: # 循環到尾部節點數據之前
if cur.item == item: # 循環過程中找到需要的數據
cur.prev.next = cur.next # 當前要刪除節點的prev,即上一個節點,上一個節點的next指向刪除後的節點
if cur.next: # 如果刪除節點的下一個節點不是尾部節點
cur.next.prev = cur.prev # 下一個節點的prev指向刪除節點的前一個節點
break # 跳出循環
cur = cur.next # 繼續循環
if __name__ == '__main__':
d = DoubleLinkList()
print(d.is_empty())
print(d.length())
d.add(1)
d.add(2)
d.append(0)
d.insert(2, 5)
d.insert(-1, 9)
d.insert(10,100)
d.travel()
print(d.is_empty())
print(d.length())