目录
一、算法原理
冒泡排序算法的原理如下:
-
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
-
对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。一趟排序之后,最后的元素应该会是最大的数。
-
针对所有的元素重复以上的步骤,除了最后一个(最后一个已经有序)。
-
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
示例演示:
待排序数组int[] arr = {3,7,2,8,4}; ,对数组升序排序。(红色为有序)
第一趟排序结果:3,2,7,4,8(四次比较)
Ⅰ、3,7比较=》3,7;
Ⅱ、7,2比较=》3,2,7;
Ⅲ、7,8比较=》3,2,7,8;
Ⅳ、8,4比较=》3,2,7,4,8
第二趟排序结果:2,3,4,7,8(三次比较)
Ⅰ、3,2比较=》2,3;
Ⅱ、3,7比较=》2,3,7;
Ⅲ、7,4比较=》3,2,4,7;
第三趟排序结果:2,3,4,7,8(两次比较)
Ⅰ、2,3比较=》2,3;
Ⅱ、3,4比较=》2,3,4;
第四趟排序结果:2,3,4,7,8(一次比较)
Ⅰ、2,3比较=》2,3;
二、算法改进
从开头的示例中可以看到,数组在第二趟排序结束之后,就已经有序,排序不需要再进行。观察规律,发现当数组已经有序时,比较时就不会再发生交换。
所以可以设置标记swapFlag=false,在每次比较中,如果发生交换,将swapFlag置为true;没发生交换,swapFlag仍为false。每一趟排序结束后,先判断swapFlag的值,如果为false,则数组已经有序,跳出循环结束排序;否则进行下一趟排序。
(参考“四、算法实现”阅读)
三、算法分析
1、时间复杂度分析
1)如果我们的数据已经有序,只需要走一趟即可完成排序。所需的比较次数C和记录移动次数M均达到最小值,即:Cmin=n-1;Mmin=0;所以,冒泡排序最好的时间复杂度为O(n)。
2)如果数组完全反序,则需要进行n-1趟排序。每趟排序要进行n-i次比较(1≤i≤n-1),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值:
所以冒泡排序的最坏时间复杂度为:O(n2) 。
综上所述:冒泡排序总的平均时间复杂度为:O(n2) 。
2、算法稳定性分析
排序算法稳定性定义:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
冒泡排序只有当前面元素大于后面元素时,才会进行交换,即,两个元素相等,不会进行交换,相对位置也就不会更改,所以冒泡排序是稳定的排序算法。
四、算法实现
1、冒泡排序算法实现
语言:Java 环境:JDK1.8
public static void bubbleSort(int[] array) {
int length = array.length;
//表示排序趟数,一共array.length-1次。
for (int i = 0; i < length - 1; i++) {
for (int j = 0; j < length - 1 - i; j++) {
if (array[j] > array[j + 1]) {
//将大值交换到后边
int temp = array[j + 1];
array[j + 1] = array[j];
array[j] = temp;
}
}
}
}
2、冒泡排序算法(改进)实现
语言:Java 环境:JDK1.8
public static void bubbleSort1(int[] array) {
int length = array.length;
//交换标志
boolean swapFlag = false;
for (int i = 0; i < length - 1; i++) {
swapFlag = false;
for (int j = 0; j < length - 1 - i; j++) {
if (array[j] > array[j + 1]) {
int temp = array[j + 1];
array[j + 1] = array[j];
array[j] = temp;
if(!swapFlag){
swapFlag = true;
}
}
}
//没发生交换退出循环
if (!swapFlag) {
break;
}
}
}