近来其实常用到qsort库函数。
用法很简单
qsort 的函数原型是void __cdecl qsort ( void *base, size_t num, size_t width, int (__cdecl *comp)(const void *, const void* ) )
其中base是排序的一个集合数组,num是这个数组元素的个数,width是一个元素的大小,comp是一个比较函数。
#include
#define MAX 1000
int cmp(const void * a, const void *b) //from small to big
{
return *(int *)a - *(int *)b;
}
int arr[MAX];
qsort(arr, MAX, sizeof(int), cmp);
------------------------------------------------------------
正如大家所知道的,快速排序算法是现在作为数据排序中很常用的算法,它集成在ANSI C的函数库中。我们经常使用快速排序,就是调用qsort函数,那么qsort函数里面到底是怎么实现的呢?我们现在就来看一看。
在这个系列的文章中,我们主要研究一下ANSI C的库函数qsort的源代码,并给出它的性能特性分析。其中使用的源代码是VS.net 2003中VC++自带的源代码,大家可以在X:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\crt\src文件夹中找到这个名为qsort.c的文件。其他C/C++编程环境也有这个文件,只是在实现上面就可能有些差异而已。
这篇文章先对qsort.c文件中的注释进行翻译,并在适当的时候进行一些分析工作。
快速排序是一个递归的过程,每次处理一个数列的时候,就从数列中选出一个数,作为划分值,然后在这个数列中,比划分值小的数移动到划分值的左边,比划分值大的数移动到划分值的右边。经过一次这样的处理之后,这个数在最终的已排序的数列的位置就确定了。然后我们把比这个数小和比这个数大的数分别当成两个子数列调用下一次递归,最终获得一个排好序的数列。
上面介绍的是基本快速排序的方法,每次把数组分成两分和中间的一个划分值,而对于有多个重复值的数组来说,基本排序的效率较低。集成在C语言库函数里面的的qsort函数,使用三路划分的方法解决这个问题。所谓三路划分,是指把数组划分成小于划分值,等于划分值和大于划分值的三个部分。
qsort的源代码基本上就分析完了,我们已经初步了解了小子数组截取(CUTOFF),三路划分,小子数组优先处理等技术的优点。
-
-
-
-
-
-
-
-
-
-
-
- #include
- #include
- #include
- #include
-
-
- #pragma optimize("t", on)
-
-
- static void __cdecl shortsort(char *lo, char *hi, size_t width,
- int (__cdecl *comp)(const void *, const void *));
- static void __cdecl swap(char *p, char *q, size_t width);
-
-
-
-
-
-
-
-
-
- #define CUTOFF 8 /* testing shows that this is good value */
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- static void __cdecl shortsort (
- char *lo,
- char *hi,
- size_t width,
- int (__cdecl *comp)(const void *, const void *)
- )
- {
- char *p, *max;
-
- while (hi > lo) {
- max = lo;
-
- for (p = lo+width; p <= hi; p += width) {
- if (comp(p, max) > 0) {
- max = p;
- }
- }
-
- swap(max, hi, width);
-
- hi -= width;
- }
- }
-
-
-
-
-
-
-
- static void __cdecl swap (
- char *a,
- char *b,
- size_t width
- )
- {
- char tmp;
- if ( a != b )
-
-
- while ( width-- ) {
- tmp = *a;
- *a++ = *b;
- *b++ = tmp;
- }
- }
-
-
-
-
-
-
-
- #define STKSIZ (8*sizeof(void*) - 2)
-
- void __cdecl qsort (
- void *base,
- size_t num,
- size_t width,
- int (__cdecl *comp)(const void *, const void *)
- )
- {
-
-
- char *lo, *hi;
- char *mid;
- char *loguy, *higuy;
- size_t size;
- char *lostk[STKSIZ], *histk[STKSIZ];
- int stkptr;
-
-
- if (num < 2 || width == 0)
- return;
-
- stkptr = 0;
-
- lo = base;
- hi = (char *)base + width * (num-1);
-
-
- recurse:
-
- size = (hi - lo) / width + 1;
-
- if (size <= CUTOFF) {
- shortsort(lo, hi, width, comp);
- }
- else {
-
-
-
-
-
-
-
-
-
-
-
-
- mid = lo + (size / 2) * width;
-
-
-
- if (comp(lo, mid) > 0) {
- swap(lo, mid, width);
- }
- if (comp(lo, hi) > 0) {
- swap(lo, hi, width);
- }
- if (comp(mid, hi) > 0) {
- swap(mid, hi, width);
- }
-
-
-
-
-
- loguy = lo;
- higuy = hi;
-
-
-
- for (;;) {
-
- if (mid > loguy) {
- do {
- loguy += width;
- } while (loguy < mid && comp(loguy, mid) <= 0);
- }
-
-
-
- if (mid <= loguy) {
- do {
- loguy += width;
- } while (loguy <= hi && comp(loguy, mid) <= 0);
- }
-
-
-
-
- do {
- higuy -= width;
- } while (higuy > mid && comp(higuy, mid) > 0);
-
-
-
- if (higuy < loguy)
- break;
-
-
-
- swap(loguy, higuy, width);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- if (mid == higuy)
- mid = loguy;
-
-
-
-
-
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- higuy += width;
- if (mid < higuy) {
- do {
- higuy -= width;
- } while (higuy > mid && comp(higuy, mid) == 0);
- }
- if (mid >= higuy) {
- do {
- higuy -= width;
- } while (higuy > lo && comp(higuy, mid) == 0);
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- if ( higuy - lo >= hi - loguy ) {
- if (lo < higuy) {
- lostk[stkptr] = lo;
- histk[stkptr] = higuy;
- ++stkptr;
- }
-
- if (loguy < hi) {
- lo = loguy;
- goto recurse;
- }
- }
- else {
- if (loguy < hi) {
- lostk[stkptr] = loguy;
- histk[stkptr] = hi;
- ++stkptr;
- }
-
- if (lo < higuy) {
- hi = higuy;
- goto recurse;
- }
- }
- }
-
-
-
-
-
-
- --stkptr;
- if (stkptr >= 0) {
- lo = lostk[stkptr];
- hi = histk[stkptr];
- goto recurse;
- }
- else
- return;
- }
阅读(2005) | 评论(0) | 转发(0) |