快速排序

快速排序思路:

1)選定一個基準元素;
2)通過一趟排序,將全部元素分紅兩部分;
3)分別對兩部分重複上述操做,直到全部元素都已排序成功。
python

由於單鏈表只能從鏈表頭節點向後遍歷,沒有prev指針,所以必須選擇頭節點做爲基準元素。這樣第二步操做的時間複雜度就爲O(n)。因爲以後都是分別對兩部分完成上述操做,所以會將鏈表劃分爲logn個段,所以時間複雜度爲O(nlogn) 。

算法

能夠看出,快排實現也是先對數據進行一遍遍歷找到關鍵值得位置,和數組不一樣的是數組能夠從兩端向中間靠攏,可是單向鏈表只能從一段開始,但用兩個指針一樣能夠實現。

數組

圖解示意:

以[4,2,5,3,7,9,0,1]爲例模擬一趟快排的過程:ui

一、初始化時,i指向鏈表首元素4;j = i +1,指向2。基準數字爲當前i 指向的數字:4。指針

j
4 2 5 3 7 9 0 1
i

二、隨後開始循環,j 當前指向2,由於2小於4,因此要把2移動到前面去。code

按照算法步驟操做:blog

  • i ++,首先 i 向後移動一位,指向2;
  • swap(i, j) ,隨後交換 i、j 位置的值,這裏面是2和2本身交換;
  • j ++,而後 j 向後移動一位,指向5;

執行一次交換後的結果以下:排序

j
4 2 5 3 7 9 0 1
i

三、接下來,因爲 j 指向的值5 大於4,直接跳過,執行j++,此時 j 指向3;遞歸

j
4 2 5 3 7 9 0 1
i

四、 j 指向的值爲3,小於4,仿照步驟2,咱們再次執行一次交換移動過程。it

  • i ++,首先 i 向後移動一位,指向5;
  • swap(i, j) ,隨後交換 i、j 位置的值,這裏面是5和3交換;
  • j ++,而後 j 向後移動一位,指向7;

交換後的結果以下:

j
4 2 3 5 7 9 0 1
i

五、j指向的值爲7,大於4,因此直接跳過,執行 j++,j 指向9:

j
4 2 3 5 7 9 0 1
i

六、同理,j 指向的值爲9,也大於4,跳過,執行 j++,j 指向0:

j
4 2 3 5 7 9 0 1
i

七、j 指向的值爲0,小於4,執行一次交換過程:

  • i ++,首先 i 向後移動一位,指向5
  • swap(i, j) ,隨後交換 i、j 位置的值,這裏面是5和0交換
  • j ++,而後 j 向後移動一位,指向1

交換後的結果以下:

j
4 2 3 0 7 9 5 1
i

八、j 指向的值爲1,小於4,咱們再執行一次交換過程

  • i ++,首先 i 向後移動一位,指向7
  • swap(i, j) ,隨後交換 i、j 位置的值,這裏面是7和1交換
  • j ++,而後 j 向後移動一位,已經超過了鏈表的長度,再也不向後移動。

交換後的結果以下:

j
4 2 3 0 1 9 5 7
i

九、最後,交換當前 i指向的值1,和4。獲得[一、二、三、0、四、九、五、7],一趟排序結束。

j
1 2 3 0 4 9 5 7
i

此時可見:4的左邊都是小於4的數字,右邊都是大於4的數字,一趟排序肯定了一個數字最終位置。

接下來,對左邊和右邊分別排序,遞歸,直到元素所有有序。

代碼實現:

# Definition for singly-linked list.
class ListNode(object):
    def __init__(self, val):
        self.val = val
        self.next = None
        
class LinkList(object):
    # 單鏈錶快速排序
    def quickSort(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head or not head.next:
            return head
        ans = ListNode(0)
        ans.next = head
        return self.sort(ans, None)
    
    def sort(self, head, end):
        if head == end or head.next == end or head.next.next == end:
            return head
        tpmHead = ListNode(0)
        # 劃分節點
        poi = head.next
        # 遍歷指針
        cur = poi
        pre = tpmHead
        # 一趟劃分
        while cur.next != end:
            # 當前節點值域小於劃分節點的值域,則將當前節點放到左側
            if cur.next.val < poi.val:
                pre.next = cur.next
                pre = pre.next
                cur.next = cur.next.next
            else:
                cur = cur.next
        # 合併臨時鏈表和原鏈表,將原鏈表接到臨時鏈表後面便可
        pre.next = head.next
        head.next = tpmHead.next
        self.sort(head, poi)
        self.sort(poi, end)
        return head.next

運行截圖:

相關文章
相關標籤/搜索