根據鏈表數據結構的知識,進行初步練習,從單鏈表的反轉、環的檢測、兩個有序鏈表的合併、判斷單向鏈表是否是迴文字符串四個題目着手,分別進行代碼實現。
首先定義單鏈表類:
# 結點類
class Node(object):
def __init__(self, data, next=None):
self.data = data
self.next = next
# 單鏈表類
class SinglyLinkedList(object):
def __init__(self):
self.head = None
self.length = 0
# 從一個列表創建單鏈表
def crt_from_list(self, L):
L.reverse()
for l in L:
self.head = Node(l, next=self.head)
self.length += 1
# 單鏈表遍歷
def lineprint(self):
if not self.head:
print("NULL")
return
p = self.head
print(p.data)
while p.next:
print(p.next.data)
p = p.next
一、單鏈表反轉
def ll_reverse(L:SinglyLinkedList):
"""
先找到尾部結點,然後從頭結點開始,依次插入尾部結點指針之後。
"""
head = L.head
tail = L.head
while tail.next:
tail = tail.next
while head != tail:
L.head = head.next
head.next = tail.next
tail.next = head
head = L.head
return L
二、單鏈表環的檢測
def is_loop(L:SinglyLinkedList):
"""
鏈表中環的檢測: 檢測一個是否存在環
方法:
使用快慢指針(分別設爲quick,slow),從head開始跑,quick步長爲2,slow步長爲1,分幾種情況:
無環:快指針quick的next或者next.next爲None,也即快指針quick走到了尾部;
有環:快指針quick的next或者next.next指向了慢指針slow;
"""
if L.head is None or L.head.next is None:
return False
quick, slow = L.head.next, L.head
while 1:
if quick == slow or quick.next == slow:
return True
elif quick is None or quick.next is None:
return False
slow = slow.next
quick = quick.next.next
三、兩個有序的鏈表合併
def merge_of_2_ll(L1:SinglyLinkedList,L2:SinglyLinkedList):
"""
有序分幾種情況:正序-正序、正序-逆序、逆序-正序、逆序-逆序,這裏僅考慮“正序-正序”的情況。
方法:
以第一個鏈表爲基礎,先構造一個哨兵結點,然後將第二個鏈表中的節點依次插入第一個鏈表;
由於是兩個有序鏈表,所以插入時只需在上次插入點之後查找即可;
"""
if not L1.head:
return L2
elif not L2.head:
return L1
# 對L1構造哨兵結點,加在其頭部之前
L0 = SinglyLinkedList()
L0.crt_from_list(L=[0])
L0.head.next = L1.head
p1, p2 = L0.head, L2.head
# 對L2鏈表中的節點,依次插入到L1
while p2:
L2.head = L2.head.next
# 如果當前p1.next不爲空,則向後遍歷:
while p1.next and p1.next.data<=p2.data:
p1 = p1.next
# 將當前p2插入其後
p2.next = p1.next
p1.next = p2
p1 = p1.next
# 更新p2
p2 = L2.head
return L1
四、判斷單向鏈表是否是迴文字符串
def is_plalidrome(L):
if not L.head:
return False
"""
1、先利用慢、快兩個指針找到鏈表中心點,分兩種情況:
偶數序列:當快指針到達末尾節點時,慢指針指向中間偏後那個節點;
奇數序列:當快指針到達末尾節點時,慢指針指向中間節點;
"""
p1, p2 = L.head, L.head
flag = 1
while p2.next:
p1 = p1.next
if p2.next.next:
p2 = p2.next.next
else:
p2 = p2.next
flag = 2
break
print("奇數序列") if flag==1 else print("偶數數序列")
print("找到中點時,p1,p2指向節點的值:",p1.data, p2.data)
"""
2、再從慢指針開始:
將慢指針指向的節點依次插入快指針後面,從而形成後半部分鏈表反轉
"""
while p1 != p2:
p3 = p1.next
p1.next = p2.next
p2.next = p1
p1 = p3
print("逆序完成時,p1,p2指向節點的值:",p1.data, p2.data)
"""
3、開始比對:從原始鏈表的表頭和p1開始一一比對,直到其中之一爲空
"""
while L.head and p1:
if L.head.data != p1.data:
print("Is not plalindrome")
return False
L.head = L.head.next
p1 = p1.next
print("Is plalindrome")
return True