您的位置:首页 > 其它

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

2015-09-07 18:17 176 查看
快速排序于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)O(N^2)。

因此,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的随机生成数组进行实验:



实验可见,当最小尺寸在20-50之间时,所优化结果为较佳。

3、快速排序是不稳定的。当希望使用稳定排序时,参见归并排序。

4、现代std库中的sort采用的技术更为复杂。当然,sort当中有其他开销,使得在本实验中表现并不良好。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: