冒泡排序(Bubble Sort),它的核心思想是:重复走访需要排序的数列(在本文中,我把每一次走访数列开始,一直到走访这一次结束,称为一趟),一次比较两个元素,如果它们的顺序错误(比如按照从小到大排列,发现前一个元素大于第二个,称为顺序错误),就把它们顺序交换过来。重复上述过程直到整个数列没有需要交换顺序的元素为止。
之所以称为冒泡排序,因为随着排序的进行,总会让较大的值“浮”到序列的顶端。
现在要对数列{1,5,3,2}进行从小到大排序。
第一趟:
第一次:{1,5,3,2}----------首先拿出来前两个元素1和5进行比较,1小于5,因此不交换两者顺序。
第二次:{1,3,5,2}----------第二次比较的时候,就要比较第二位和第三位,分别是5和3,5大于3,交换顺序。
第三次:{1,3,2,5}----------第三次比较的时候,就要比较第三位和第四位,分别是5和2,5大于2,交换顺序。
第一趟结束,确定了一个最大值:5,放在最后一位。冒泡排序中第一个泡已经浮上水面了。
第二趟:
第一次: {1,3,2,5}-----------任然比较前两个元素1和3,1小于3,顺序不变
第二次: {1,2,3,5}-----------比较第二位和第三位,分别是3和2,3大于2,交换顺序。
第二趟这里已经结束了,第三个位置不需要再和第四个位置比较了,因为第一趟结束已经把最大数排到了最后一位(也就是第四位)。此时,又决定了数列中第二大数:3,放到了倒数第二位。
第二个泡也浮出了水面,它是数列中的第二大,放在了倒数第二位。
第三趟:
第一次: {1,2,3,5}------------比较数列中的前两位1和2,1小于2,顺序不变。
第三趟也结束了,因为,第四、三位置的数,分别是最大数值和第二大数值,无需比较。
此时,第三个泡也浮出了水面,它就是数列中的第三大数:2,排到倒数第三位(正数第二位),因此剩余的最小值1,排在第一位。
冒泡排序到此结束。
结论与代码实现:
因此,4个数,共走了3趟,其中第一趟3次,第二趟2次,第三趟1次。
由上可推出,n个数,共需要走(n-1)趟,其中第 i 趟,需要比较的次数为 j =(n - i)
#include<stdio.h> //输出数组 void printArr(int a[], int n) { for (int i = 0; i < n; i++) { printf("%d--", a[i]); } printf("\n"); } //冒泡排序 void BubbleSort(int a[], int n) { for (int i = 1; i <= n - 1; i++)//i为比较趟数,从第一趟开始,共需要(n-1)趟 { for (int j = 1; j <= n - i; j++)//j为每一趟比较的次数,每趟最少比较一次,因此从1开始。第i趟,共需要比较(n-i)次, { if (a[j - 1] > a[j])//前面的大于后面的,换位 { int temp = a[j]; a[j] = a[j - 1]; a[j - 1] = temp; } } } printArr(a, n); } void main() { int a[4] = { 1, 3, 5, 2 }; BubbleSort(a, 4); getchar(); }
(上述代码完全是按照本文的解释意思所写,可能与网上版本不太相同,其实核心思想是一样的。我的 i 和 j 从1开始,是为了方便理解趟数和每趟比较的次数)
冒泡排序的改进:
这里该有疑问了,当非最后一趟未发生一次顺序交换的时候,说明该数列已经排序OK了,那么剩下的每一趟,不都是在做无用功吗?
因此,我们可以改进冒泡排序的算法。只需要在每一趟开始的时候,定义一个bool类型的标识变量sign,如果一趟结束了,标识符未发生改变,说明该数列已经排序完成。
//冒泡排序 void BubbleSort(int a[], int n) { bool sign; for (int i = 1; i <= n - 1; i++)//i为比较趟数,从第一趟开始,共需要(n-1)趟 { sign = false;//在每一趟开始的时候,定义一个标识,为false。 for (int j = 1; j <= n - i; j++)//j为每一趟比较的次数,每趟最少比较一次,因此从1开始。第i趟,共需要比较(n-i)次, { if (a[j - 1] > a[j])//前面的大于后面的,换位 { int temp = a[j]; a[j] = a[j - 1]; a[j - 1] = temp; sign = true; } } if(sign==false)//如果一趟结束了,sign仍为false,说明这一趟一次交换也没进行,说明序列已经排序完成。 { break; } } printArr(a, n); }
正序数列(例如{1,2,3,4})走一趟,标识sign仍为false,break退出循环,共比较(n-1)次,因此最佳情况下,时间复杂度为n。
时间复杂度:
最好情况,纯正序数列,比较(n-1)次,时间复杂度为n,
普通情况,比较n(n-1)/2次,时间复杂度为n^2,
平均时间复杂度:n^2。
稳定性:
冒泡排序是一种稳定的排序。