Quick Sort

输入:一个待排序的数组A以及排序范围[left, right]。

输出:排序后的数组。

算法思想

快速排序算法属于分治算法:将数组的最后一个元素与其他元素进行一系列的比较与交换(划分),插入到这个元素在排好序后所处的位置。此时,该元素的左边的元素都比该元素小,右边的元素都比该元素大,则该问题被划分成了三个小问题:1) 该元素左边的待排序子数组 ;2) 该元素右边的待排序子数组;3) 该元素(已经被排序)。

划分

算法导论中对划分的伪码描述如下(数组下标从1开始,而不是0):

PARTITION(A, left, right):
    x = A[right]
    i = left - 1
    for j = left to r - 1:
        if A[j] <= x:
            i = i + 1
            exhcange A[i] with A[j]
    exchange A[i + 1] with A[right]  // 将最后一个元素插入到正确的位置
    return i + 1

该伪代码在for循环中将已经比较过的子数组分成两个部分,A[0, i]为比A[right]小的元素,A[i + 1, j - 1]为比A[length - 1]大的元素。若A[j] <= A[right],则A[0, i]扩充到A[0, i + 1],否则A[i + 1, j - 1]扩充到[i + 1, j]。

例子

输入:A = [5, 2, 6, 8, 1, 3, 9, 7, 4],left = 0,right = 8

  1. 5 > 4,不交换,A = [5, 2, 6, 8, 1, 3, 9, 7, 4];
  2. 2 < 4,交换,A = [2, 5, 6, 8, 1, 3, 9, 7, 4];
  3. 6 > 4,不交换,A = [2, 5, 6, 8, 1, 3, 9, 7, 4];
  4. 8 > 4,不交换,A = [2, 5, 6, 8, 1, 3, 9, 7, 4];
  5. 1 < 4,交换,A = [2, 1, 6, 8, 5, 3, 9, 7, 4];
  6. 3 < 4,交换,A = [2, 1, 3, 8, 5, 6, 9, 7, 4];
  7. 9 > 4,不交换,A = [2, 1, 3, 8, 5, 6, 9, 7, 4];
  8. 7 > 4,不交换,A = [2, 1, 3, 8, 5, 6, 9, 7, 4];
  9. 此时蓝色部分都比4小,红色部分都比4大,将4与8进行交换,得到A = [2, 1, 3, 4, 5, 6, 9, 7, 8]即完成第一次插入,此后只需要对蓝色部分与红色部分分别递归地进行上述操作即可完成整个数组的排序。

快速排序完整算法(Python实现)

from random import randint
from random import uniform

def quick_sort(array_to_sort, left, right):
    array_to_sort = array_to_sort.copy()
    if left >= right:
        return array_to_sort  # needn't to sort
    
    stack = [left, right]
    while stack:
        high = stack.pop(-1)
        low = stack.pop(-1)
        if low >= high:
            continue
        
        random_number = int(uniform(low, high))  # randomization
        array_to_sort[random_number] , array_to_sort[high] = array_to_sort[high], array_to_sort[random_number]
        pivot_element = array_to_sort[high]
        i = low - 1
        for j in range (low, high):
            if array_to_sort[j] <= pivot_element:
                i = i + 1
                array_to_sort[j], array_to_sort[i] = array_to_sort[i], array_to_sort[j]
        array_to_sort[i + 1], array_to_sort[high] = array_to_sort[high], array_to_sort[i + 1]
        stack.extend([low, i, i + 2, high])
    
    return array_to_sort

if __name__ == '__main__':
    array_size = int(input("Please input the length of array:"))
    array_to_sort = [randint(0, 1000) for i in range (0, array_size)]
    print("Init\tarray:", array_to_sort)
    
    # start sort
    print("\n\n")
    print("####################")
    print("## Start sorting! ##")
    print("####################")
    print("")
    
    print("Quick\t\t sort:", quick_sort(array_to_sort, 0, len(array_to_sort) - 1))

时间复杂度

设对一个长度为n的数组进行快速排序需要\(T(n)\)的时间,由于该算法将待排序数组划分成两个未排序子数组以及一个单独的元素,我们可以假设每次划分都从中间进行划分,则对每个子数组的排序所消耗的时间近似等于\(T(\frac{1}{2})\)。每次划分都需要遍历整个数组,耗时\(O(n)\)。综上,有:
\[ T(n) = 2T(\frac{1}{2}) + n \]
这个递归定义的方程可以使用Master定理进行求解,最终可得时间复杂度为\(O(n\log_2n)\)。

上一篇:Leetcode 19. 删除链表的倒数第N个节点


下一篇:python快速选择排序