快速排序

一、分而治之

什么十快速排序算法的最好情况?

每次正好中分:T(N) = O(NlogN)

void Quicksort(ElementType A[], int N)
{
    pivot = 从A[]中选一个主元;
    将S = { A[] \ pivot } 分成2个独立子集:
        A1 = { a属于S | a≤ pivot } 和
        A2 = { a属于S | a≥ pivot };
    A[] = Quicksort(A1, N1) U { pivot} U Quicksort(A2, N2);
}
伪代码

 

选主元

  • 随机取pivot?rand()函数不便宜啊!
  • 取头、中、尾的中位数
    • 例如8、12、3的中位数就是8
    • 测试一下pivot不同的取法对运行速度有多大影响?
ElementType Median3(ElementType A[], int Left, int Right)
{
    int Center = (Left + Right) / 2;
    if(A[Left] > A[Center])
        Swap(&A[Left], &A[Center]);
    if(A[Left] > A[Right])
        Swap(&A[Left], &A[Right]);
    if(A[Center] > A[Right])
        Swap(&A[Center], &A[Right]);
    /* A[Left] <= A[Center] <= A[Right] */
    Swap(&A[Center], &A[Right-1]);
    /* 只需要考虑A[Left+1] ... A[Right-2] */
    return A[Right-1];
}
选pivot

 

小规模数据的处理

  • 快速排序的问题
    • 用递归。。
    • 对小规模的数据(例如N不到100)可能还不如插入排序快
  • 解决方案
    • 当递归的数据规模充分小,则停止递归,直接调用简单排序(例如插入排序)
    • 在程序中定义一个Cutoff的阈值 -- 课后去时间一下,比较不同的Cutoff对效率的影响

 

实现算法

void Quicksort(ElementType A[], int Left, int Right)
{
    if(Cutoff <= Right-Left) {
        Pivot = Median3(A, Left, Right);
        i = Left; j = Right - 1;
        for( ; ; ) {
            while(A[++i] < Pivot) { }
            while(A[--j] > Pivot) { }
            if(i < j)
                Swap(&A[i], &A[j]);
            else
                break;
        }
        Swap(&A[i], &A[Right-1]);
        Quicksort(A, Left, i-1);
        Quicksort(A, i+1, Right);
    } else
        Insertion_Sort(A+Left, Right-Left+1);
}

void Quick_Sort(ElementType A[], int N)
{
    Quicksort(A, 0, N-1);
}

 

posted @ 2018-05-11 16:16  习惯就好233  阅读(140)  评论(0编辑  收藏  举报