冒泡排序也是基于比较的排序。每一趟将一个元素(最大/最小)放入最终的位置,如劣图所示:
或者将从后向前冒泡,或者从前向后冒泡。
类似于插入排序,总共有n-1趟排序组成。从位置pos到最终的位置上是有序的,一个冒泡过程就是找出0~pos-1上的最大值,放在pos的位置,之后pos位置向前挪一位,到序列有序时冒泡停止。
从冒泡的过程可以看出,冒泡算法需要一个嵌套的循环,时间复杂度为O(N2)。在最好的情况下,即序列有序,也需要扫描一遍确定,时间复杂度为O(N).
一个序列的排序过程如下:
初始序列:9 7 8 4 1 6
一趟一次:7<->9 8 4 1 6
一趟二次:7 8<->9 4 1 6
一趟三次:7 8 4<->9 1 6
一趟四次:7 8 4 1<->9 6
一趟五次:7 8 4 1 6<->9
。。。
最终序列:1 4 6 7 8 9
算法源码如下:
void bubble_sort(int arr[], int count)
{
int i, j, tmp;
int swap;
for(i = count-1; i > 0; i--)
{
swap = false;
/*将大数向右冒泡,每次确定一个元素的位置*/
for(j = 0; j <= i - 1; j++)
{
if(arr[j] > arr[j + 1])
{
tmp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = tmp;
swap = true;
}
}
/*序列已经有序的话直接退出*/
if(!swap)
{
break;
}
}
}
虽然冒泡排序的时间复杂度和插入排序一样,但是实际的测试时间却长了很多,如截图所示:
由此可见说xx的时间复杂度是O(N2),xxx的时间复杂度是O(N),xxx执行比xx快。这样说是不对的。
冒泡和插入排序对比后发现,冒泡比插入排序慢这么多的根本原因是冒泡排序使用了大量的交换操作。所以应该尽量避免使用明显的交换操作。为了证明交换的确会影响程序效率,我对程序做了一点修改,主要是记录未排序的最大值和位置将其与未排序的序列末尾元素做交换,从而减少了交换并完成冒泡。源码如下:
void pro_bubble_sort(int arr[], int count)
{
int i, j, max, pos;
for(i = count - 1; i > 0; i--)
{
max = arr[i];
pos = i;
for(j = 0; j < i; j++)
{
if(max < arr[j])
{
max = arr[j];
pos = j;
}
}
arr[pos] = arr[i];
arr[i] = max;
}
}
相同的随机数输入得到的时间如下截图:
可见交换对程序执行时间的影响。