Skip to content

Latest commit

 

History

History
93 lines (57 loc) · 2.89 KB

q_sort.md

File metadata and controls

93 lines (57 loc) · 2.89 KB

QuickSort

快排(partition-exchange sort)是一种高效的排序方式,它的平均时间复杂度为O(nlogn),最坏时间复杂度为O(n^2)。但是稍微努力,就可以避免最坏的情况出现。

How it works ?

快排的思想属于分治法(Divide-and-conquer algorithm)。它将一个大的序列划分为两个子序列:较小的和较大的。然后递归的对子序列排序。步骤如下:

  1. 选取基准值:从数组中选取一个基准值 pivot
  2. 分区:对数组重新排序,使基准左边的数据都小于(等于)基准值,其后面的数据都大于基准值。经过分区之后,此时基准在其合适的位置。
  3. 递归排序字串: 对各个字串递归重复以上的过程。

观察以上步骤,有两步是关键

  1. 选择基准(pivot)
  2. 分区运算(partition operation)

How to select an pivot from array ?

基准点的选择是很关键的,最坏的情况是选择了最小的数值作为基准点。这样,它的时间复杂度达到最大O(N^2)

因此也就有有了很多种选择基准点的方式,最简的是 取首或者尾元素作为基准点。还有一些常见的如median-of-three quicksort算法,来定位基准点。

Partition Array Process

这里选取最后一个元素作为基准点,来演示一下大概的排序过程:

当然实现的时候可以在进行优化,使用双指针来减少交换次数,如下,

Time complexity

时间复杂度计算

Array

void q_sort(ArrayList *array, unsigned int left, unsigned int right, compare_func cmp)
{
    if (left >= right)
        return;

    // first select the mid one as the datum mark
    unsigned int mid = (left + right) / 2, startIndex = left;
    // swap
    Swap(array->elements[right], array->elements[mid]);
    for (unsigned int i = left; i < right; i++)
    {
        if (cmp(array->elements[i], array->elements[right]) < 0)
        {
            Swap(array->elements[startIndex++], array->elements[i]);
        }
    }

    // swap the
    Swap(array->elements[right], array->elements[startIndex]);
    // recursive subArray
    q_sort(array, left, startIndex - 1, cmp);
    q_sort(array, startIndex + 1, right, cmp);
}

void sort(ArrayList *array, compare_func cmp)
{
    q_sort(array, 0, array->length - 1, cmp);
}

Linked

Related

  1. merge sort
  2. heap sort
  3. Divide and Conquer

References

  1. QuickSort Wiki
  2. QuickSort