《C算法》笔记10:快速排序

快速排序于1960年由Hoare发明,公认为效率最高的排序算法之一,广泛应用于C++标准库中。快速排序是典型的分治算法,或者确切的说,是典型的先治后分(conquer-divide)算法:

#define LT(a, b) (a < b)
#define EXCH(a, b) {int t = a; a = b; b = t;}
#define CMXCH(a, b) if(LT(b, a)) EXCH(a, b)
void quick_sort(int *a, int l, int r)
{
    if(r <= l) return;
    int i = quick_partition(a, l, r); //conquer
    quick_sort(a, l, i - 1); //divide
    quick_sort(a, i + 1, r);
}

quick_partition将a[r]元素置为标准位,比a[r]小的移到数组前端,比a[r]大的移到数组后端,最后返回a[r]在新数组中的位置。

int quick_partition(int *a, int l, int r)
{
    int i = l - 1, j = r;
    int v = a[r];
    while(true)
    {
        while(v > a[++ i]);
        while(v < a[-- j]) if(i == j) break;
        if(i >= j)
            break;
        EXCH(a[i], a[j]);
    }
    EXCH(a[i], a[r]);
    return i;
}

1、当待排序数组有序时,快速排序性能将严重退化。退化表现在每次选取的a[r]永远最大,造成递归函数调用层数为N。同理,待排序数组反序时,快速排序时间复杂度退化到 O(N2)
因此,r直接决定了快速排序的性能。一般用随机选取或者三中值法来选取r。
2、由前文所述,插入排序在部分有序的数组中性能较好。当递归函数已经得到较小尺寸的数组时,可采用插入排序,以减少不必要的函数调用开销。

void quick_sort_v3m(int *a, int l, int r, int d) // d为“较小的尺寸”
{
    if(r - l <= d) 
    {
        insert_sort2(a, l, r);
        return;
    }

    int m = (l + r) / 2;
    EXCH(a[m], a[r - 1]);
    CMXCH(a[r - 1], a[r]);
    CMXCH(a[l], a[r - 1]);
    CMXCH(a[r - 1], a[r]);

    int i = quick_partition(a, l + 1, r - 1);
    quick_sort_v3m(a, l, i - 1, d);
    quick_sort_v3m(a, i + 1, r, d);
}

在本地VS2012环境下,(CPU:i5-3470)对一长度为5M的随机生成数组进行实验:
《C算法》笔记10:快速排序_第1张图片
实验可见,当最小尺寸在20-50之间时,所优化结果为较佳。
3、快速排序是不稳定的。当希望使用稳定排序时,参见归并排序。
4、现代std库中的sort采用的技术更为复杂。当然,sort当中有其他开销,使得在本实验中表现并不良好。

你可能感兴趣的:(算法)