將單向鏈表按某值劃分成左邊小、 中間相等、 右邊大的形式-python3

基礎解:荷蘭國旗問題(筆試時可用,簡單直接,但不穩定)

        將所有的節點遍歷得到鏈表的長度,再遍歷一次將所有節點放置到一個數組中,對這個數組進行partition調整(荷蘭國旗問題),再將每個數組中每個節點串起來即可。

進階解:按照原鏈表各個節點的對應順序將鏈表調整成三部分,小於num的、等於num的,大於num的,之後再將三個連起來即可。

代碼如下:

#coding=utf-8
'''
將單向鏈表按某值劃分成左邊小、 中間相等、 右邊大的形式
【 題目】 給定一個單向鏈表的頭節點head, 節點的值類型是整型, 再給定一個
整 數pivot。 實現一個調整鏈表的函數, 將鏈表調整爲左部分都是值小於 pivot
的節點, 中間部分都是值等於pivot的節點, 右部分都是值大於 pivot的節點。
除這個要求外, 對調整後的節點順序沒有更多的要求。 例如: 鏈表9->0->4->5-
>1, pivot=3。 調整後鏈表可以是1->0->4->9->5, 也可以是0->1->9->5->4。 總
之, 滿 足左部分都是小於3的節點, 中間部分都是等於3的節點(本例中這個部
分爲空) , 右部分都是大於3的節點即可。 對某部分內部的節點順序不做 要求。
進階: 在原問題的要求之上再增加如下兩個要求。
在左、 中、 右三個部分的內部也做順序要求, 要求每部分裏的節點從左 到右的
順序與原鏈表中節點的先後次序一致。 例如: 鏈表9->0->4->5->1, pivot=3。
調整後的鏈表是0->1->9->4->5。 在滿足原問題要求的同時, 左部分節點從左到
右爲0、 1。 在原鏈表中也 是先出現0, 後出現1; 中間部分在本例中爲空, 不再
討論;右部分節點 從左到右爲9、 4、 5。 在原鏈表中也是先出現9,然後出現4,
最後出現5。
如果鏈表長度爲N,時間複雜度請達到O(N),額外空間複雜度請達到O(1)。
'''
class Node(object):
    """單向鏈表的結點"""
    def __init__(self,elem):
        self.elem=elem
        self.next=None

class SingleLinkList(object):
    """單鏈表"""
    def __init__(self,node=None):
        """構造函數"""
        self.__head=node    #頭節點
    def getHead(self):
        return self.__head
    def travel(self):
        """遍歷鏈表"""
        cur=self.__head
        while cur!=None:
            print(cur.elem,end=" ")
            cur=cur.next
        print("")
    def add(self,item):
        """鏈表頭部添加元素
        O(1)
        """
        node=Node(item)
        node.next=self.__head
        self.__head=node
    def listPartition1(self,num):#這種方法最快,但做不到穩定性,數組需要額外空間。
        #普通問題
        #時間複雜度是 O(N),空間複雜度是 O(N)
        #首先遍歷一遍鏈表,得到鏈表的長度,將鏈表元素依次放到數組中,然後利用類似於快速排序中的partition 思想進行分割
        #partition完之後再串成鏈表
        if self.__head is None: #空鏈表
            return self.__head
        cur=self.__head
        i=0
        while cur:  #遍歷一次鏈表,統計元素個數即鏈表長度
            cur=cur.next
            i+=1
        #將鏈表中的每個元素依次放入到數組中
        nodeArr=[]
        cur=self.__head
        for j in range(0,i):
            nodeArr.append(cur)
            cur=cur.next
        # print(i)

        #進行類似快速排序的partition
        nodeArr=self.arrPartition(nodeArr,num)
        #重新連接各個鏈表節點
        for q in range(1,i):
            nodeArr[q-1].next=nodeArr[q]
        nodeArr[i-1].next=None
        return  nodeArr
    def arrPartition(self,nodeArr,num):
        left=-1
        right=len(nodeArr)
        index=0
        while index<right:
            if nodeArr[index].elem<num:
                left += 1
                nodeArr[left],nodeArr[index]=nodeArr[index],nodeArr[left]   #交換
                index+=1
            elif nodeArr[index].elem==num:
                index+=1
            else:
                right -= 1
                nodeArr[right], nodeArr[index] = nodeArr[index], nodeArr[right] ##交換

        return nodeArr
    def listPartition2(self,num):#測試通過
        '''
     *  進階問題: 保證各部分內部的順序與原來鏈表中各個節點的順序相同
     *  時間複雜度是 O(N),空間複雜度是 O(1)
     *  考察 利用有限的幾個變量來調整鏈表的代碼實現能力。

    1.將鏈表分爲三部分:small,equal,more
                      small:2->1->null
                      equal:5->5->null
                      more:9->7->8->null
    2.將small、equal、more三個鏈表重新串起來
    3.整個過程需要特別注意對null節點的判斷和處理
        '''
        less=Node(None)
        endless=Node(None)
        equal=Node(None)
        endequal=Node(None)
        more=Node(None)
        endmore=Node(None)

        #every node distributed to three lists
        while self.__head:
            Next=self.__head.next
            self.__head.next=None
            if self.__head.elem<num:
                if less.elem is None:
                    less=self.__head
                    endless=self.__head
                else:
                    endless.next=self.__head
                    endless=endless.next
            elif self.__head.elem==num:
                if equal.elem is None:
                    equal=self.__head
                    endequal=self.__head
                else:
                    endequal.next=self.__head
                    endequal=self.__head
            elif self.__head.elem>num:
                if more.elem is None:
                    more =self.__head
                    endmore=self.__head
                else:
                    endmore.next=self.__head
                    endmore=self.__head
            self.__head=Next
        # small and equal reconnect
        if endless.elem and equal.elem:
            endless.next=equal
            endequal=endequal if endequal.elem else endless
        # all reconnect
        if endequal.elem:
            endequal.next=more
            endmore=endmore if endmore.elem else endequal
        res=equal if equal.elem else more
        res=less if less.elem else res   #返回鏈表頭節點
        return res
    def printLinkedList(self,node):
        print("Linked List:")
        while node.next:
            print(node.elem,end=" ")
            node=node.next
        print(node.elem)
    print("")
if __name__=="__main__":
    s1 = SingleLinkList()
    s1.add(7)
    s1.add(9)
    s1.add(1)
    s1.add(8)
    s1.add(3)
    s1.add(5)
    s1.add(2)
    s1.add(5)
    s1.add(5)
    s1.add(4)
    s1.add(3)
    s1.travel()
    # res=s1.listPartition1(5)
    # s1.printLinkedList(res[0])
    res=s1.listPartition2(6)    #bug:如果沒有等於num的鏈表就斷掉了
    s1.printLinkedList(res)

 

運行結果如下:

等程序無bug再粘

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