https://www.bilibili.com/video/av53583801/?p=20
學習筆記
1 Single Link List
圖片來源:https://www.bilibili.com/video/av53583801/?p=19
class Node(object):
def __init__(self,value,next=None):
self.value = value
self.next = next
class SingleLinkList(object):
def __init__(self,node=None):
self.__head = node # 初始化頭指針指向 None
def is_enmpty(self):
"""鏈表是否爲空"""
return self.__head==None
def length(self):
"""鏈表長度"""
cur = self.__head # 頭節點
count = 0
while(cur): # 當前指針不指向 None 時候
count+=1
cur = cur.next
return count
def travel(self):
"""遍歷鏈表"""
cur = self.__head # 頭節點,私有變量
while (cur): # 當前指針不指向 None 時候
print(cur.value,end=" ")
cur = cur.next
print("")
def append(self,item):
"""鏈表尾部添加元素"""
node = Node(item,None) # 創建一個新節點
if self.is_enmpty(): # 如果是空鏈表,頭指針直接指向新的節點
self.__head = node
else:
cur = self.__head
while(cur.next):
cur = cur.next
cur.next = node
def add(self,item):
"""鏈表頭部添加元素"""
node = Node(item) # 新建節點
node.next = self.__head # 新建結點指向原來的第一個節點
self.__head = node # 頭部節點指向新建的節點(新的第一個節點)
def insert(self,pos,item):
"""鏈表任意位置添加元素,位置從0開始"""
if pos <= 0: # 插入的位置小於等於0,則等價於在鏈表頭部添加元素
self.add(item)
elif pos > self.length()-1: # 大於鏈表長度,等價於在鏈表尾部添加元素
self.append(item)
else:
cur = self.__head
for i in range(pos-1): # 遍歷到插入到位置的前一個位置
cur = cur.next
node = Node(item) # 新建一個節點
node.next = cur.next
cur.next = node
def search(self,item):
"""查找元素是否在鏈表中,返回布爾值"""
cur = self.__head
while(cur):
if cur.value == item:
return True
else:
return False
def remove(self,item):
"""移除第一個匹配的元素"""
"""單指針,cur.next = cur.next.next"""
"""雙指針,pre.next = cur.next"""
pre = None
cur = self.__head
while(cur):
if cur.value == item:
if cur == self.__head: # 匹配上了第一個節點,此時 pre 爲空,沒有next,所以單獨討論
self.__head = cur.next
else:
pre.next = cur.next # 刪除節點
break # 刪完以後就應該退出
else: # 向後走一步
pre = cur
cur = cur.next
if __name__ == "__main__":
ll = SingleLinkList()
print("is_empty:",ll.is_enmpty())
print("length",ll.length())
ll.append(1)
print("is_empty:",ll.is_enmpty())
print("length",ll.length())
ll.append(2)
ll.add(8)
ll.append(3)
ll.append(4)
ll.append(5)
ll.append(6)
ll.insert(-1,9)
ll.insert(3,100)
ll.insert(10,200)
ll.travel()
result = ll.search(9)
print(result)
result = ll.search(300)
print(result)
ll.remove(9)
ll.travel()
ll.remove(200)
ll.travel()
ll.remove(100)
ll.travel()
output
is_empty: True
length 0
is_empty: False
length 1
9 8 1 100 2 3 4 5 6 200
True
False
8 1 100 2 3 4 5 6 200
8 1 100 2 3 4 5 6
8 1 2 3 4 5 6
2 Double Link List
圖片來源:https://www.bilibili.com/video/av53583801/?p=23
is_enmpty
、length
、travel
、search
同 Single Link List,完全可以繼承 Single Link List 類!remove 改動較大,注意要 remove 的元素是最後一個節點的時候的情況
class Node(object):
def __init__(self,value,pre=None,next=None):
self.value = value
self.pre = pre
self.next = next
class DoubleLinkList(object):
def __init__(self,node=None):
self.__head = node # 初始化頭指針指向 None
def is_enmpty(self): # 同 SingleLinkList
"""鏈表是否爲空"""
return self.__head==None
def length(self): # 同 SingleLinkList
"""鏈表長度"""
cur = self.__head # 頭節點
count = 0
while(cur): # 當前指針不指向 None 時候
count+=1
cur = cur.next
return count
def travel(self): # 同 SingleLinkList
"""遍歷鏈表"""
cur = self.__head # 頭節點,私有變量
while (cur): # 當前指針不指向 None 時候
print(cur.value,end=" ")
cur = cur.next
print("")
def append(self,item):
"""鏈表尾部添加元素"""
node = Node(item,None) # 創建一個新節點
if self.is_enmpty(): # 如果是空鏈表,頭指針直接指向新的節點
self.__head = node # 注意只有一個node的話,pre 和 next 都是空,不要以爲 pre 是 head
else:
cur = self.__head
while(cur.next):
cur = cur.next
cur.next = node
node.pre = cur # 相比於 SingleLinkList 新增
def add(self,item):
"""鏈表頭部添加元素"""
node = Node(item) # 新建節點
node.next = self.__head # 新建結點指向原來的第一個節點
self.__head.pre = node # 相比於 SingleLinkList 新增
self.__head = node # 頭部節點指向新建的節點(新的第一個節點)
def insert(self,pos,item):
"""鏈表任意位置添加元素,位置從0開始"""
if pos <= 0: # 插入的位置小於等於0,則等價於在鏈表頭部添加元素
self.add(item)
elif pos > self.length()-1: # 大於鏈表長度,等價於在鏈表尾部添加元素
self.append(item)
else: # 相比與 SingleLinkList
cur = self.__head
for i in range(pos): # 遍歷到插入的位置
cur = cur.next
node = Node(item) # 新建一個節點
node.next = cur # 先讓新建的節點搭在原來的列表上
node.pre = cur.pre
cur.pre = node # 再斷開原有鏈表的鏈接,搭在新建列表上
node.pre.next = node
def search(self,item): # 同 SingleLinkList
"""查找元素是否在鏈表中"""
cur = self.__head
while(cur):
if cur.value == item:
return True
else:
return False
def remove(self,item):
"""移除第一個匹配的元素"""
"""不同於 singleLinkList,這裏不需要定義兩個指針了"""
cur = self.__head
while(cur):
if cur.value == item:
if cur == self.__head: # 匹配上了第一個節點,此時 pre 爲空,沒有next,所以單獨討論
self.__head = cur.next
else:
cur.pre.next = cur.next # 刪除節點
if cur.next: # 這裏判斷是否是最後一個節點(最後一個節點的next爲none,none沒有pre)
cur.next.pre = cur.pre
break # 刪完以後就應該退出
else: # 向後走一步
if cur.next:
cur = cur.next
if __name__ == "__main__":
ll = DoubleLinkList()
print("is_empty:",ll.is_enmpty())
print("length",ll.length())
ll.append(1)
print("is_empty:",ll.is_enmpty())
print("length",ll.length())
ll.append(2)
ll.add(8)
ll.append(3)
ll.append(4)
ll.append(5)
ll.append(6)
ll.insert(-1,9)
ll.insert(3,100)
ll.insert(10,200)
ll.travel()
result = ll.search(9)
print(result)
result = ll.search(300)
print(result)
ll.remove(9)
ll.travel()
ll.remove(200)
ll.travel()
ll.remove(100)
ll.travel()
結果
is_empty: True
length 0
is_empty: False
length 1
9 8 1 100 2 3 4 5 6 200
True
False
8 1 100 2 3 4 5 6 200
8 1 100 2 3 4 5 6
8 1 2 3 4 5 6
3 Single Cycle Link List
圖片來源:https://www.bilibili.com/video/av53583801/?p=25
Single Cycle Link List 在 Single Link List 的基礎上改動還是比較大的,特別是 remove
的時候。search
同 Single Link List
class Node(object):
def __init__(self,value,next=None):
self.value = value
self.next = next
class SingleCycleLinkList(object):
def __init__(self,node=None):
self.__head = node # 初始化頭指針指向 None
if node: # 新建一個不爲空的循環鏈表
node.next = self.__head
def is_enmpty(self): # 同 SingleLinkList
"""鏈表是否爲空"""
return self.__head==None
def length(self):
"""鏈表長度"""
if self.is_enmpty():
return 0
else:
cur = self.__head # 頭節點
count = 1
while(cur.next != self.__head):
count+=1
cur = cur.next
return count
def travel(self):
"""遍歷鏈表"""
if self.is_enmpty():
return 0
else:
cur = self.__head # 頭節點,私有變量
while (cur.next != self.__head): # 當前指針不指向 None 時候
print(cur.value,end=" ")
cur = cur.next
print(cur.value,end=" ") # 退出循環的時候,cur 指向尾節點,但尾節點的元素並沒有打印
print("")
def append(self,item):
"""鏈表尾部添加元素"""
node = Node(item,None) # 創建一個新節點
if self.is_enmpty(): # 如果是空鏈表,頭指針直接指向新的節點
self.__head = node
node.next = node # 新增節點自己指向自己形成cycle
else:
cur = self.__head
while(cur.next != self.__head): # 遍歷讓cur指向尾節點
cur = cur.next
cur.next = node
node.next = self.__head # 形成 cycle
def add(self,item):
"""鏈表頭部添加元素"""
node = Node(item) # 新建節點
if self.is_enmpty():
self.__head = node # 頭指向新增的節點
node.next = node # 新增節點自己指向自己形成cycle
else:
cur = self.__head
while(cur.next!=self.__head): # 遍歷讓cur指向尾節點(因爲是循環鏈表,所以尾部要指向新增的頭)
cur = cur.next
node.next = self.__head # 新建結點指向原來的第一個節點
self.__head = node # 頭部節點指向新建的節點(新的第一個節點)
cur.next = node #相比於 SingleLinkList 新增,尾部指向頭部
def insert(self,pos,item): # 同 SingleLinkList
"""鏈表任意位置添加元素,位置從0開始"""
if pos <= 0: # 插入的位置小於等於0,則等價於在鏈表頭部添加元素
self.add(item)
elif pos > self.length()-1: # 大於鏈表長度,等價於在鏈表尾部添加元素
self.append(item)
else:
cur = self.__head
for i in range(pos-1): # 遍歷到插入到位置的前一個位置
cur = cur.next
node = Node(item) # 新建一個節點
node.next = cur.next
cur.next = node
def search(self,item):
"""查找元素是否在鏈表中,返回布爾值"""
if self.is_enmpty():
return False
else:
cur = self.__head
while(cur.next!=self.__head): # 遍歷 1-n-1
if cur.value == item:
return True
else:
return False
if cur.value == item: # 同travel,退出循環的時候,cur 指向尾節點,但尾節點的元素並沒有遍歷
return True
else:
return False
def remove(self,item):
"""移除第一個匹配的元素"""
if self.is_enmpty():
return
else:
pre = None
cur = self.__head
while(cur.next!=self.__head):
if cur.value == item: ### 匹配到了第一個
if cur == self.__head: # 匹配上了第一個節點,此時 pre 爲空,沒有next,所以單獨討論
end = self.__head
while(end.next!=self.__head): # 遍歷定位到尾部指針
end = end.next
self.__head = self.__head.next
end.next = self.__head
else: ### 匹配到了 2-n-1,刪除操作同單鏈表
pre.next = cur.next # 刪除節點
return # 刪完以後就應該退出
else: # 向後走一步
pre = cur
cur = cur.next
if cur.value == item: ### while 循環外表示遍歷到了最後一個節點(只有一個節點/不止一個節點),匹配到了第n個
if cur.next == self.__head: # 這表示匹配的是鏈表中最後一個節點
pre.next = self.__head
else: #cur == self.__head: # 鏈表只有一個節點,此時 pre 爲 none,不能用上面的一句話
self.__head = None
if __name__ == "__main__":
ll = SingleCycleLinkList()
print("is_empty:",ll.is_enmpty())
print("length",ll.length())
ll.append(1)
print("is_empty:",ll.is_enmpty())
print("length",ll.length())
ll.append(2)
ll.add(8)
ll.append(3)
ll.append(4)
ll.append(5)
ll.append(6)
ll.insert(-1,9)
ll.insert(3,100)
ll.insert(10,200)
ll.travel()
result = ll.search(9)
print(result)
result = ll.search(300)
print(result)
ll.remove(9)
ll.travel()
ll.remove(200)
ll.travel()
ll.remove(100)
ll.travel()
output
is_empty: True
length 0
is_empty: False
length 1
9 8 1 100 2 3 4 5 6 200
True
False
8 1 100 2 3 4 5 6 200
8 1 100 2 3 4 5 6
8 1 2 3 4 5 6
4 小結
Single Link List 是情況最簡單的,在這個的基礎上,我們改進實現了 Double Link List 和 Single Cycle Link List,三種鏈表的測試樣例是一樣的,所以如果 coding 沒有問題的話,結果是一樣的!
主要實現瞭如下功能:
is_empty()
:是否爲空length()
:鏈表的長度traval()
:遍歷鏈表,打印出來search(item)
:查找元素是否在鏈表中,返回 boolean 值add(item)
:在鏈表的第一個位置添加元素append(item)
:在鏈表的最後一個位置添加元素insert(pos,item)
:在鏈表的指定位置插入元素remove(item)
:刪除掉匹配到的第一個元素
在 coding 的時候一定要注意以下的邊界情況是否要單獨討論:
- 鏈表爲空
- 鏈表只有一個元素
- 要對鏈表的第一個元素進行操作
- 要對鏈表的最後一個元素進行操作
然後插入的時候,最好不要先動原來的鏈表,先讓新節點搭上去,然後再改原來的鏈表。