數據結構與算法(四):Python實現單鏈表的反轉、環的檢測、兩個有序鏈表的合併、判斷單向鏈表是否是迴文字符串

根據鏈表數據結構的知識,進行初步練習,從單鏈表的反轉、環的檢測、兩個有序鏈表的合併、判斷單向鏈表是否是迴文字符串四個題目着手,分別進行代碼實現。

首先定義單鏈表類:

# 結點類
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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章