冒泡排序法又称为交换排序法,是由观察水中冒泡的变化启发而来。冒泡排序是由第一个元素开始,比较相邻元素大小,若大小顺序有误,则对调后再进行下一个元素的比较。如此扫描过一次之后就可确保最后一个元素是位于正确的顺序。接着再逐步进行第二次扫描,直到完成所有元素的排序关系为止。
例如:数组:6、4、9、8、3、5 数组长度len=6
原始值:6、4、9、8、3、5
第一次扫描过程:首先比较6和4,6>4 交换顺序:4、6、9、8、3、5,接着继续比较6和9,6<9不用交换顺序保持原顺序:4、6、9、8、3、5,然后再比较9和8,9>8交换顺序:4、6、8、9、3、5,然后比较9和3,9>3交换序:4、6、8、3、9、5,最后比较9和5,9>5 交换顺序:4、6、8、3、5、9
因此第一次扫描的结果为:4、6、8、3、5、9 总比较次数len-1=5次
第二次扫描过程:第二次扫描仍从头开始,但因最后一个元素是整个数组中值最大的,所以第二次扫描只需比较到倒数第二个元素即可。
首先比较4和6,4<6 保持顺序不变,为:4、6、8、3、5、9;然后比较6和8,6<8顺序不变,仍为:4、6、8、3、5、9 然后接着比较8和3,8>3交换顺序为:4、6、3、8、5、9,最后比较8和5,8>5交换顺序为:4、6、3、5、8、9;
因此第二次扫描的结果为:4、6、3、5、8、9; 总比较次数len-2=4次
第三次扫描过程:第三次扫描仍从头开始,但因最后两个元素是已排好序,所以第三次扫描只需比较到倒数第三个元素即可。
首先比较4和6,4<6 保持顺序不变,为:4、6、3、5、8、9;然后比较6和3,6>3交换顺序:4、3、6、5、8、9
接着比较6和5,6>5交换顺序:4、3、5、6、8、9;最后比较6和8,6<8顺序不变:4、3、5、6、8、9;
因此第三次扫描的结果为:4、3、5、6、8、9;总比较次数len-3=3次
第四次扫描过程:第四次扫描仍从头开始,但因最后三个元素是已排好序,所以第四次扫描只需比较到倒数第四个元素即可。
首先比较4和3,4>3交换顺序:3、4、5、6、8、9;最后比较4和5,4<5顺序不变:3、4、5、6、8、9
因此第四次扫描的结果为:3、4、5、6、8、9 总比较次数len-4=2次
第五次扫描过程:第五次扫描仍从头开始,但是最后4个元素已排好序,所以第四次扫描只需比较到倒数第五个元素即可。
比较3和4,顺序不变:3、4、5、6、8、9 总比较次数len-5=1次
经过5次扫描就把长度为6的数组完成了所有排序;
从以上整个过程可以发现冒泡排序具有以下性质:
1、最坏情况和平均情况均需比较(n-1)+(n-2)+……+2+1=(n-1)*n/2次;
2、时间复杂度为O(n^2),最好情况只需扫描一次,发现没有交换的动作即表示已经排好序,所以只需比较n-1次,时间复杂度为O(n);
3、由于冒泡排序只需涉及到相邻两元素之间的比较与交换,不会影响其他元素的顺序,所以是稳定的。
4、只需一个额外的空间,所以空间复杂度为O(1),空间复杂度最佳。
5、这种排序法适用于数据量小或有部分数据已经排过序的数组。
传统冒泡排序法程序实现:
/*
[名称]:传统冒泡排序法
*/
#include<stdio.h>
void maopao(int a[],int len);
void swap(int &,int &);
int main()
{
int a[6]={6,5,9,7,2,8};
int len=6;
printf("原数组数据为:");
for(int i=0;i<6;i++)
printf("%d ",a[i]);
printf("\n");
maopao(a,len);
printf("原数组排序后为:");
for(int i=0;i<6;i++)
printf("%d ",a[i]);
printf("\n");
getchar();
return 0;
}
void maopao(int a[],int _len)
{
while(--_len)
{
for(int i=0;i<_len;i++)
{
if(a[i]>a[i+1])
swap(a[i],a[i+1]);
}
printf("第%d次排序后的结果:",6-_len);
for(int i=0;i<6;i++)
printf("%d ",a[i]);
printf("\n");
}
}
void swap(int &x,int &y)
{
x=x+y;
y=x-y;
x=x-y;
}
输出结果:
传统冒泡排序有个明显的缺点,即不管数据是否已排序完成都固定执行n*(n-1)/2次,可以通过在程序中加入一个判断语句来判断何时终止程序。
/*
[名称]:改良冒泡排序法
*/
#include<stdio.h>
void bubble(int a[],int len);
void swap(int &,int &);
int main()
{
int a[6]={6,5,9,7,2,8};
int len=6;
printf("原数组数据为:");
for(int i=0;i<6;i++)
printf("%d ",a[i]);
printf("\n");
bubble(a,len);
printf("原数组排序后为:");
for(int i=0;i<6;i++)
printf("%d ",a[i]);
printf("\n");
getchar();
return 0;
}
void bubble(int a[],int _len)
{
while(--_len)
{
int flag=0; //flag用来判断是否执行交换的动作
for(int i=0;i<_len;i++)
{
if(a[i]>a[i+1])
{
swap(a[i],a[i+1]);
flag++; //如果执行过交换,则flag不为0
}
}
if(flag==0)
break;
printf("第%d次排序后的结果:",6-_len);
for(int i=0;i<6;i++)
printf("%d ",a[i]);
printf("\n");
}
}
void swap(int &x,int &y)
{
x=x+y;
y=x-y;
x=x-y;
}
输出结果为: