快速排序(單路快排/雙路快排/三路快排) Python版筆記

1.快速排序

時間複雜度 :最好O(nlogn),最壞O(n^2)
空間複雜度 :O(1)

在這裏插入圖片描述
Partition主要思想是:將小於v和大於v的部分都放到索引值i的左邊

def _partition(nums,l,r):
    '''
    將數組第一個數視爲base,目的是將所有小數放到左邊,大數放到右邊,返回正確分割的索引
    '''
    base = nums[l]  #即圖片的v
    j = l+1
    for i in range(l+1, r+1):
        if nums[i] < base:  #遍歷數組剩下的數,如果小於base則依次放在base的後面
            nums[i], nums[j] = nums[j], nums[i]
            j += 1
        print(nums)
    nums[l], nums[j-1] = nums[j-1], nums[l]   #把base值放到正確的位置
    print(nums)
    return j-1

def _quick_sort(nums,l,r):
    if l < r:
        m = _partition(nums,l,r)
        _quick_sort(nums,l,m-1)
        _quick_sort(nums,m+1,r)


def quick_sort(nums):
    l, r = 0, len(nums)-1
    _quick_sort(nums,l,r)

當待排序數組是一個近乎有序的序列時,容易產生最壞O(n^2)的時間複雜度。
改進辦法:base隨機選取

def _partition_random(nums,l,r):
    ind = random.randint(l,r)
    nums[l], nums[ind] = nums[ind], [l]
    ##### 後面的內容同_partition,故省略 #####

2.雙路快排

當待排序數組是一個數值重複率非常高的序列時,容易產生最壞O(n^2)的時間複雜度。

產生下圖所示的情況,左右子樹不均衡:
在這裏插入圖片描述
在這裏插入圖片描述
Partition主要思想是:將小於v的部分放到指針i(i爲遍歷用指針)的左邊,將大於v的部分都放到指針j的右邊,延用隨機選base的思路。等於v時使用交換的方式處理。

import random

def _partition_doubule(nums, l, r):
    ind = random.randint(l, r)
    nums[l], nums[ind] = nums[ind], nums[l]
    base = nums[l]
    i, j = l+1, r
    while True:
        while i <= r and nums[i] < base:  # 不能改爲nums[i] <= base, 因爲這種方式則                      # 會將連續出現的這些值歸爲其中一方,使得兩棵子樹不平衡
            i += 1
        while j >= l + 1 and nums[j] > base:  # 不能改爲nums[j] >= base.
            j -= 1
        if i > j:
            break
        else:
            nums[i], nums[j] = nums[j], nums[i]
            i += 1
            j -= 1
    nums[j], nums[l] = nums[l], nums[j]
    return j


def _quick_sort(nums, l, r):
    if l < r :
        m = _partition_doubule(nums, l, r)
        _quick_sort(nums, l, m - 1)
        _quick_sort(nums, m + 1, r)


def quick_sort(nums):
    l, r = 0, len(nums)-1
    _quick_sort(nums,l,r)

3.三路快排

在這裏插入圖片描述
Partition主要思想是:將小於v的部分放到指針lt左邊,將大於v的部分放到指針gt右邊。考慮到v有重複值的情況,遇到等於v的情況,將i指針右移。

import random


def _partition(nums, l, r):
    ind = random.randint(l, r)
    nums[l], nums[ind] = nums[ind], nums[l]
    base = nums[l]
    lt = l  # nums[l+1...lt] < base
    gt = r + 1  # nums[gt...r] > base
    i = l + 1  # nums[lt+1...i] == base
    while (i < gt):
        # i==gt時表示已經比較結束
        if (nums[i] < base):
            nums[i], nums[lt+1] = nums[lt+1], nums[i]
            lt += 1
            i += 1
        elif (nums[i] > base):
            nums[i], nums[gt-1] = nums[gt-1], nums[i]
            gt -= 1
        else:  # nums[i] == base
            i += 1
        print(nums)
    nums[l], nums[lt] = nums[lt], nums[l]
    print(nums)
    return lt, gt


def _quick_sort(nums, l, r):
    if l < r:
        lt, gt = _partition(nums, l, r)
        _quick_sort(nums, l, lt - 1)
        _quick_sort(nums, gt, r)


def quick_sort(nums):
    l, r = 0, len(nums) - 1
    _quick_sort(nums, l, r)

引用:
1.快速排序時間複雜度爲O(n×log(n))的證明
2.排序算法—快速排序,隨機快速排序和雙路快排(python版)
3.歸併排序、快速排序、二路快排、三路快排python實現
4.十大經典排序算法(動圖演示)

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