冒泡和选择排序该被踢出教材了

jackyjkchen 2010-08-05 08:50:39
加精
实用排序算法(复杂度小于等于O(n^2))中效率最低但实现并不是最简单的的两个,C、C++教材却总喜欢拿来大讲特讲,非常不利于初学者养成“程序效率”的思维。

实际上,各种排序算法里,除了堆排序实现较为复杂外,从代码量的角度,大多数算法都不比冒泡、选择算法复杂多少。

举几个高速的排序算法的例子,这些才适合进入教材

鸽巢排序,排序字节串、宽字节串最快的排序算法,计数排序的变种(将计数缓冲区大小固定,少一次遍历开销),速度是STL中std::sort的20多倍,更重要的是实现极其简单!缺点是需要一个size至少等于待排序数组取值范围的缓冲区,不适合int等大范围数据

void PigeonholeSort(BYTE *array, int length)
{
int b[256] = {0};
int i,k,j = 0;
for(i=0; i<length; i++)
b[array[i]]++;
for(i=0; i<256; i++)
for(k=0; k<b[i]; k++)
array[j++] = i;
}



多一次遍历的计数排序,排序字节串的话速度约是鸽巢排序的一半

void CountingSort(BYTE *array, int length)
{
int t;
int i, z = 0;
BYTE min,max;
int *count;
min = max = array[0];
for(i=0; i<length; i++)
{
if(array[i] < min)
min = array[i];
else if(array[i] > max)
max = array[i];
}
count = (int*)malloc((max-min+1)*sizeof(int));
for(i=0; i<max-min+1; i++)
count[i] = 0;
for(i = 0; i < length; i++)
count[array[i]-min]++;

for(t = 0; t <= 255; t++)
for(i = 0; i < count[t-min]; i++)
array[z++] = (BYTE)t;
free(count);
}


快速排序,快排最标准的递归实现,速度约是std::sort的一半

void swap(BYTE *a,BYTE *b)
{
BYTE tmp;
if ( a != b )
{
tmp = *a;
*a = *b;
*b = tmp;
}
}

int partition(BYTE *arr,int left, int right)
{
int i = left - 1, j = right;
BYTE v = arr[right];
while(1)
{
while(arr[++i] < v);
while(arr[--j] > v)
if(j == 1)
break;
if(i >= j)
break;
swap(&arr[i],&arr[j]);
}
swap(&arr[i],&arr[right]);
return i;
}

void quicksort(BYTE *arr, int left, int right)
{
if (left < right)
{
int i = partition(arr,left,right);

quicksort(arr,left,i-1);
quicksort(arr,i+1,right);
}
}

void QuickSort(BYTE *array,int length)
{
quicksort(array,0,length-1);
}


这是速度与std::sort相当的三路划分快排

void swap(BYTE *a,BYTE *b)
{
BYTE tmp;
if ( a != b )
{
tmp = *a;
*a = *b;
*b = tmp;
}
}

void quicksort(BYTE *arr, int left, int right)
{
if (left < right)
{
BYTE v = arr[right];
int i = left - 1,j = right,p = left - 1,q = right,k=0;
while (1)
{
while (arr[++i] < v);
while (arr[--j] > v)
if(j==left)
break;
if (i >= j)
break;
swap(&arr[i], &arr[j]);
if(arr[i] == v)
{
p++;
swap(&arr[p],&arr[i]);
}
if(arr[j] == v)
{
q--;
swap(&arr[q],&arr[j]);
}
}
swap(&arr[i],&arr[right]);
j = i - 1;
i++;
for(k=left; k<=p; k++,j--)
swap(&arr[k],&arr[j]);
for(k=right-1; k>=q; k--,i++)
swap(&arr[k],&arr[i]);
quicksort(arr,left,j);
quicksort(arr,i,right);
}
}

void QuickSort(BYTE *array,int length)
{
quicksort(array,0,length-1);
}



相当简单的梳排序,效率是std::sort的三分之一

void CombSort(BYTE *arr, int size)
{
UINT gap = size, swapped = 1, i = 0;
BYTE swap = 0;
while ((gap > 1) || swapped)
{
if (gap > 1)
gap = gap / 1.3;
swapped = 0;
i = 0;
while ((gap + i) < size)
{
if (arr[i] - arr[i + gap] > 0)
{
swap = arr[i];
arr[i] = arr[i + gap];
arr[i + gap] = swap;
swapped = 1;
}
++i;
}
}
}


LSD基数排序,与std::sort速度相当,但是需要一个与输入缓冲一样大的缓冲区

#define R 256

#define digit(a, d) ( a >> 8*d )

static BYTE *aux;

void radix_sort(BYTE *arr, int left, int right)
{
if(left < right)
{
int d = 0;
for(d=3; d>=0; d--)
{
int i=0, j=0, count[R+1];
for(j=0; j<R; j++)
count[j] = 0;
for(i=left; i<=right; i++)
count[digit(arr[i],d) + 1]++;
for(j=1; j<R; j++)
count[j] += count[j-1];
for(i=left; i<=right; i++)
aux[count[digit(arr[i],d)]++] = arr[i];
for(i=left; i<=right; i++)
arr[i] = aux[i-1];
}
}
}

void RadixSort(BYTE *array,int length)
{
aux = (BYTE*)malloc(length);
radix_sort(array,0,length-1);
free(aux);
}


归并排序,效率越是std::sort的六分之一,通常的实现是递归,但和快排不同,归并改循环极其容易

void merge(BYTE *array, int low, int mid, int high)
{
int i, k;
BYTE *temp = (BYTE *) malloc(high-low+1);
int begin1 = low;
int end1 = mid;
int begin2 = mid + 1;
int end2 = high;

for (k = 0; begin1 <= end1 && begin2 <= end2; ++k)
if(array[begin1]<array[begin2])
temp[k] = array[begin1++];
else
temp[k] = array[begin2++];
while(begin1<=end1)
temp[k++] = array[begin1++];
while(begin2<=end2)
temp[k++] = array[begin2++];
for (i = 0; i < (high-low+1); i++)
array[low+i] = temp[i];
free(temp);
}

void merge_sort(BYTE *array, UINT first, UINT last)
{
UINT mid,i;
for(mid=1; mid<=last-first; mid += mid)
for(i=first; i<=last-mid; i+=mid+mid)
merge(array,i,i+mid-1,min(i+mid+mid-1,last));
}

void MergeSort(BYTE *array, UINT length)
{
merge_sort(array,0,length-1);
}
...全文
43922 845 打赏 收藏 转发到动态 举报
写回复
用AI写文章
845 条回复
切换为时间正序
请发表友善的回复…
发表回复
qqggy 2013-05-01
  • 打赏
  • 举报
回复
学习了,谢分享
winassembly 2013-04-30
  • 打赏
  • 举报
回复
看到这里,只能说学无止尽。
HHasdsda 2013-04-30
  • 打赏
  • 举报
回复
现在大部分不都是二分法吗
u010021391 2013-04-30
  • 打赏
  • 举报
回复
学习,感谢分享
木犀花香 2013-04-29
  • 打赏
  • 举报
回复
过来学习一下排序算法!
就是那个党伟 2013-04-25
  • 打赏
  • 举报
回复
冒泡容易理解是真的。 给一个刚学C的人,来一个快排,目测他会扔下C然后去打游戏了。 我刚学C的时候,书上的汉诺塔一直弄不明白,明明说上写着递归很简单,看的懂,单就是真正明白不了。 等CPP也学完,回来看的时候,突然觉得,快排和汉诺塔,还有12358,蛮easy的。 楼主偏激了~
YRICH 2013-03-05
  • 打赏
  • 举报
回复
对于我等谭浩强都没看完的菜鸟来说,冒泡才能懂
千树之影 2013-03-05
  • 打赏
  • 举报
回复
从教学角度看,当然要从逻辑最简单的冒泡选择开始讲。 从实用角度看,100个元素以下自己写冒泡选择最方便,大点的数据量直接上qsort等现成函数了,自己去写完全浪费时间。
千树之影 2013-03-05
  • 打赏
  • 举报
回复
引用 43 楼 jackyjkchen 的回复:
引用 42 楼 bobo364 的回复: 书里写的只是个入门,入门而已,算法每天都在增加,任何书也写不完,所以书里放这两个东西也有它的道理,说明排序这回事,并不是要效率 鸽巢排序明明最简单也最高效,为什么不用? 实际上“用简单的XXX说明道理”就是个错误,事实已经证明了,用简单的TC来学习C/C++是中国教育界的一大失败!
连int值都不能处理的排序算法,想作为入门算法?
wyz3000gh 2013-03-04
  • 打赏
  • 举报
回复
新手从简单易理解的开始学习还是要好些的
wodeyunyuandehuiyi 2013-03-04
  • 打赏
  • 举报
回复
学习了 很给力
丨Barneyx 2013-03-04
  • 打赏
  • 举报
回复
LZ正解啊!
五的二次方 2013-01-30
  • 打赏
  • 举报
回复
菜鸟一个,学习了,谢谢楼主
hetengfei_ 2013-01-29
  • 打赏
  • 举报
回复
如果你的排序源 的数据量不大, 你按什么 方法都 行!
hetengfei_ 2013-01-29
  • 打赏
  • 举报
回复
楼主完全正确。 以实战中,较快是插入排序法。 更快是 二分法+插入排序法 如果数量实在太多,二分法+插入排序法 都 算慢得无法接受, 还有另一种方法: 就是 分段插入排序法 --这个词是我发明的。 不知你们能不能理解, 意思是, 先按数的大小,分成一些段数, 比如,Int32 的数,可以 分成sqrt(2的32次方) 段, 每段是 0 到 sqrt(2的32次方), sqrt(2的32次方) 到 2*sqrt(2的32次方), 2 *sqrt(2的32次方) 到 3*sqrt(2的32次方), ... 到(sqrt(2的32次方)-2)*(sqrt(2的32次方)-1) 到(sqrt(2的32次方)-1)*sqrt(2的32次方), 这种叫做二维分段排序法, 如果,要更快, 还有三维,四维的! (三维就是 先进行第一次分段,再段内又进行一次分段, 然后才做段内的数据排序)
nadleeh 2013-01-29
  • 打赏
  • 举报
回复
引用 楼主 jackyjkchen 的回复:
实用排序算法(复杂度小于等于O(n^2))中效率最低但实现并不是最简单的的两个,C、C++教材却总喜欢拿来大讲特讲,非常不利于初学者养成“程序效率”的思维。 实际上,各种排序算法里,除了堆排序实现较为复杂外,从代码量的角度,大多数算法都不比冒泡、选择算法复杂多少。 举几个高速的排序算法的例子,这些才适合进入教材 鸽巢排序,排序字节串、宽字节串最快的排序算……
光考虑时间开销,物理开销呢? 如果是嵌入式系统,内存不够的话还是去快排?还去连续开栈递归?一不小心就不知到死到哪里去了. 冒泡和选择等简洁易懂,并且十分适合于小数量级的排序.
eddy0727 2013-01-28
  • 打赏
  • 举报
回复
正在学习中,这里高手真多啊。。。。。开心
ztcwlj 2012-05-24
  • 打赏
  • 举报
回复
学习(冒泡和选择排序..)
chaofengwang09 2012-05-23
  • 打赏
  • 举报
回复
[Quote=引用 43 楼 的回复:]
引用 42 楼 bobo364 的回复:
书里写的只是个入门,入门而已,算法每天都在增加,任何书也写不完,所以书里放这两个东西也有它的道理,说明排序这回事,并不是要效率

鸽巢排序明明最简单也最高效,为什么不用?

实际上“用简单的XXX说明道理”就是个错误,事实已经证明了,用简单的TC来学习C/C++是中国教育界的一大失败!
[/Quote]

TC 是失败 能详细些吗?
ohayou 2012-05-23
  • 打赏
  • 举报
回复
先把语文学好,搞清楚“效率”这个词的意思。
加载更多回复(825)

69,369

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧