冒泡排序是常常使用的排序,面试中也常常用到。
他的特点是:
1.简单
冒泡排序的逻辑是相邻元素进行比较和交换,经过一轮排序至少可以确定一个有序的元素。
那么可以得出结论:排序n个元素,需要n-1轮排序。
for (x =0 ;x <len-1 ;++x)
经过一轮排序,可以把最大或者最小的元素移动到数组的一边,下一轮在排序时,减少排序元素的数目。
for (y = len-1; y > x; --y)
比较a[y]-1 和a[y]的大小,来决定排序的方式
if (a[y-1] > a[y])
swap(&a[y-1],&a[y]);
2.稳定性
排序稳定的意思是说排序前后,key相同的元素的的相对位置不变。那么这个有什么用呢?
有些算法的前提就是稳定的排序,所以这根具体的算法有关系。
比如:对字符串从小到大排序,ast aqt
排序按照第1,2,3 。。。进行比较
第二次比较的是是ast 在aqt前面,按照第三个字符比较时,排序不稳定,ast可能跑到aqt的后面,这样排序就造成了错误。
普通的冒泡排序的效率太低了,时间复杂度是O(n2),下面是提高冒泡排序的一些方法。
1.设置标志位,记录在一轮排序中是否有过元素交换
比如 5个元素 1 2 3 4 5,显然这已经是有序的数组。但是算法不知道啦,算法不能看到这个数组已经是有序的。
所以需要给他安上一双“眼睛”,去监视一些情况。正常需要5个元素,需要4轮循环。
但是只要有交换情况,就给改变标志位,在一轮循环之后去检查这个标志位,那么在第一轮循环结束后,我就结束排序的过程了。
int i,j,flag;
for (i = 0;i <len-1;++i)
{
flag = 0;//需要在一轮循环开始时,初始化为0
for (j =len-1;j>i;--j)
{
if(a[j-1] > a[j])
swap(&a[j-1],&a[j]);
flag = 1;
}
if(flag==0)
break;//退出循环
}
2.上一次交换的位置,比如 经过一轮排序 ,已经形成了这样的序列1 2 3 7 5 。默认的排序是经过一轮排序,确定一个元素。
实际上可能是确定了好几个元素,为了减少交换的次数,需要从上次交换的元素的位置开始排序,而不是默认的一次增加一个的排序。
int i,j,flag,swap=0;
for (i = 0;i <len-1;i = swap)//取消默认的+1,减少排序次数。
{
flag = 0;
for (j =len-1;j>i;--j)
{
if(a[j-1] > a[j])
swap(&a[j-1],&a[j]);
flag = 1;
swap = j;//获得一轮循环的交换的下标。
}
if(flag==0)
break;//退出循环
}
总结:经过测试,冒泡排序经过优化之后的效率和没有优化的冒泡排序差不多。所以,冒泡排序本身效率就不高,就不要想着提高什么效率了,
真的需要提高效率就选择别的排序方法。
最后说一下冒泡的记忆口诀:
外加加 内减减
内大于外
比较外-1 和外