冒泡算法讲解
我发现,很多人写的所谓冒泡算法代码,其实是错的,这里给一份正确的代码,并讲解正确的冒泡代码的特征程序代码:
#include <stdio.h> #include <stdlib.h> #include <time.h> //这个宏,定义交换两个数a,b,其中t是交换临时变量 #define SWAP(a, b) do {int t = a; a = b; b = t; } while(0) int bubblesort_t(int* arr, int len) { for (int ed = len-1; ed > 0; --ed) // ed 控制内循环的结束边界 { for (int iter = 0; iter < ed; ++iter) // 内循环,it遍历从 0 至 ed-1 { if ( !(arr[iter] <= arr[iter+1]) ) // 大小比较,比较方式直接决定排序的方式 { SWAP(arr[iter], arr[iter+1]); // 对不符合比较结果的,使其交换,以符合比较的方式 } } } return 0; } int main() { int nums[100]; int n_nums = 10, n; srand((unsigned)time(NULL)); /* 初始化随机数 */ for (n=0; n < n_nums; n++) { nums[n] = rand() % 99 + 1; /*利用rand()函数产生随机数,%99表示产生随机数不超过三位数*/ } printf("排序前:\n"); for (n=0; n < n_nums; n++) { printf("%d ", nums[n]); /*在显示屏上输出由上面随机产生的数字*/ } bubblesort_t(nums, n); printf("\n排序后:\n"); for (n=0; n < n_nums; n++) { printf("%d ", nums[n]); } scanf("%*s"); return 0; }
main函数可以不管,主要看bubblesort_t这个函数,有这样几个特点:
1 外层变量控制内层循环的结束条件,而非起始点
2 二重循环里,内层循环的控制变量和终止条件必然是一自加一自减
3 如果是无经过优化的冒泡,总共要比较len*(len-1)/2次
4 每次比较,总是比较相邻的两个数,不会发生其它位置的数的比较
不符合这些特点的,那你的算法很可能是错的,但不排除一个复杂化的版本,1-3都不符合,但却排序结果是对的,
比如直接用一个len的平方(即内外循环都直接用len而不变化)的写法,虽然正确,但不是严格意义上的冒泡,并且效率比冒泡更低下。
相对而言,选择排序则比冒泡容易写对,因为内外循环方式一致,代码也好写,所谓10个新手9个写错冒泡,真是一点都不夸张
以下解释一下,1,2两个特点,为什么会这样。
首先,冒泡的定义是每次比较相邻的两个数,每一轮的比较,会把最值交换到最后一次参与比较的地方,即循环的终点的地方
然后,不管已经确定好的最值,把剩下的数做同样的事
好了,从以上定义里,我们知道,最后一次参与比较的地方,即循环的终点的地方,一轮的比较结束后,那里是最大值或者最小值
那个数是不会再参与下一轮的比较的,那么,每一轮,起点不会变,变的是终点,
所以外层循环的变量,要控制内层循环,即每一轮的终点的值
我们假设S是起点,E是终点:
S _ _ _ ... _ _ _ E
内层循环的比较,起点是不变的,并且从起点不断向终点比较,内层循环从左向右
但是,终点在每一轮比较完以后,下一轮就不需要再比较了,E点每一轮就会左移一格,也就是说,外层循环从右向左
好了,这样以来,你定义从左向右,不管是下标递增还是递减,内外层循环的变量,总是一个加的话,另一个必然是减
否则,那你终点的值,根本连是不是最值都不能保证,只多试几组数就会发现排序并未完成,也就是说那个算法是错的
以上分析就到这里了,当你看明白这文章以后,相信你以后,一眼就可以看出一个自称冒泡算法的代码,是不是错的
[ 本帖最后由 御坂美琴 于 2010-10-6 16:54 编辑 ]