冒泡排序
冒泡排序是一种简单的排序思想,即通过比较和交换,使较小(或较大)的数据逐渐向一端移动。
算法原理
以从小到大排序为例:
1.遍历数据(除了最后一个)。
2.使被遍历的数据与其后一个数据作比较,若比后一个大,则交换。
3.重复 1,2 直到排序完成(优化)。
算法可视化
图片来自http://sc.chinaz.com/jiaobendemo.aspx?downloadid=8201830910379
每次遍历总会使得某一个数据被安排在正确的位置上。
那么我们只要遍历 “n - 1” 次即可完成排序。
实现
简单实现
- 详细注释:
//===============冒泡排序简单实现
void BubbleSort(int* array,int count)
//array为欲排序数组的指针,通过这个指针可以直接操作传入的数组
//count为数组元素个数
{
int i, j, temp;//temp在交换数据时作为第三方变量使用
for (j = 0; j < count - 1; j++)
{
//j < count - 1外层循环进行了 “count - 2” 次
//使得前 “count - 1” 个数据排在了正确的位置上,那么剩下一个数据当然也在正确的位置上
for (i = 0; i < count - 1 - j; i++)
{
//对于 i < count - 1 - j
//每次内层循环总会把一个数据放置得尽可能靠后,也就是说靠后的 j 个数据已经排好序,没必要继续遍历
if (array[i] > array[i+1]
{//如果当前数据比后面的数据大
//交换数据
//这是三个语句,为了简洁就写在一起了
temp = array[i+1]; array[i+1] = array[i]; array[i] = temp;
}
}
}
}
- 去掉注释:
//===============冒泡排序简单实现
void BubbleSort(int* array,int count)
{
int i, j, temp;
for (j = 0; j < count - 1; j++)
{
for (i = 0; i < count - 1 j; i++)
{
if (array[i] > array[i + 1])
{
temp = array[i + 1]; array[i + 1] = array[i]; array[i] = temp;
}
}
}
}
优化
对于上述算法,我们知道:外层循环每循环一次,就会把一个数据排在正确的位置,那么如果有一个或多个数据本来就在正确的位置上呢?
思考,如果向我们刚才研究的 BubbleSort() 函数中传入这样一组数据:
2 1 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
我们发现,排序实际上在第一次外层循环结束时就已经完成了。
而外层循环却保证自身会循环 “count - 1” 次,所以即使排序已经完成,算法依然会傻傻地运行下去:
for (j = 0; j < count - 1; j++){}
为了解决这个问题,我们只要判断某次外层循环是否发生过数据交换即可。
如果本次没有发生交换,那么说明排序已经结束,可以直接输出结果。
那么我们可以定义一个标志位来实现这样的算法:
int flag;
- 代码如下:
//===============冒泡排序优化版本
void BubbleSort_adv(int * a,int count)
{
int i, j, temp, flag;//标志,0 为未发生交换,1 为发生过交换
for (j = 0; flag == 1; j++)
{//外层循环条件变为 “已发生交换”
flag = 0;//内层循环开始时,我们认为还未发生交换
for (i = 0; i < count - 1 - j; i++)
{
if (a[i] > a[i + 1])
{
temp = a[i + 1]; a[i + 1] = a[i]; a[i] = temp;
flag = 1;//发生交换,flag置 1
}
}
}
}
- 去掉注释:
//===============冒泡排序优化版本
void BubbleSort_adv(int * a,int count)
{
int i, j, temp, flag;
for (j = 0; flag == 1; j++)
{
flag = 0;
for (i = 0; i < count - 1 - j; i++)
{
if (a[i] > a[i + 1])
{
temp = a[i + 1]; a[i + 1] = a[i]; a[i] = temp;
flag = 1;
}
}
}
}
使用clock()函数,比较算法的运行效率:
- 代码:
//重复跑一千万次
......
start = clock();
for ( i = 1; i <= 10000000; i++)
{
BubbleSort(a.array,9);//为了方便对排序序列的初始化,这里是将数组包装在了结构体中。
a = b;//结构体可以直接赋值。
//关于结构体赋值,这里存在一些问题,不过不会影响本次的结果,我们下次再讨论。
}
printf("优化前:%lfs\n",(double) (clock() - start)/CLK_TCK);
start = clock();
for ( i = 1; i <= 10000000; i++)
{
BubbleSort_adv(a.array,9);
a = b;
}
printf("优化后:%lfs\n",(double) (clock() - start)/CLK_TCK);
......
- 输出:
反向
以上给出的算法均与算法可视化一致,为从小到大排列。
若想改变排序方向,只需要做一个微小的改动
//===============冒泡排序优化版本(从大到小)
void BubbleSort_adv(int * a,int count)
{
int i, j, temp, flag;
for (j = 0; flag == 1; j++)
{
flag = 0;
for (i = 0; i < count - 1 - j; i++)
{
if (a[i] < a[i + 1])//改动这里的符号
{
temp = a[i + 1]; a[i + 1] = a[i]; a[i] = temp;
flag = 1;
}
}
}
}