冒泡排序
冒泡排序是每次都对相邻的两个数进行比较,如果逆序则交换的一种排序方法。每一次排序后都有一个元素归位,归位元素不再参与下一趟比较。
举例
对数组[-2, 5, 4, 6, 1, 2]进行由小到大冒泡排序:
- 第一趟:
- 比较[-2, 5] -2, 5, 4, 6, 1, 2
- 比较[5, 4] 交换 -2, 4, 5, 6, 1, 2
- 比较[5, 6] -2, 4, 5, 6, 1, 2
- 比较[6, 1] 交换 -2, 4, 5, 1, 6, 2
- 比较[6, 2] 交换 -2, 4, 5, 1, 2, 6
- 第一趟排序结束,最后一位数6已经归位
- 第二趟:
- 比较[-2, 4] -2, 4, 5, 1, 2, 6
- 比较[4, 5] -2, 4, 5, 1, 2, 6
- 比较[5, 1] 交换 -2, 4, 1, 5, 2, 6
- 比较[5, 2] 交换 -2, 4, 1, 2, 5, 6
- 第二趟排序结束,5,6已经归位
- 第三趟:
- 比较[-2, 4] -2, 4, 1, 2, 5, 6
- 比较[4, 1] 交换 -2, 1, 4, 2, 5, 6
- 比较[4, 2] 交换 -2, 1, 2, 4, 5, 6
- 第三趟排序结束,4,5,6已经归位
- 第四趟:
- 比较[-2, 1] -2, 1, 2, 4, 5, 6
- 比较[1, 2] -2, 1, 2, 4, 5, 6
- 第四趟排序结束,2,4,5,6已经归位
- 第五趟:
- 比较[-2, 1] -2, 1, 2, 4, 5, 6
- 第五趟排序结束,1,2,4,5,6已经归位
- 排序结束。
- 总结:从上述过程中可以看出对于规模为n的数组,需要进行n-1趟排序;每一趟排序比较的次数在递减,第一趟排序比较(n-1)次,第二趟比较(n-2)次…第n-1趟排序比较1次。
- 时间复杂度:O(n²)
- 稳定性:冒泡排序始终是对相邻的两个数进行比较,例如排序 2, 4, 2, 6,排序后第一个2仍然是在第二个前面,是稳定的排序算法。
优化
从上面的例子可以看出,实际上在第3趟排序之后数组就已经有序了,也就是第4和第5趟排序并没有进行元素交换。可以设置一个标志位flag来标记某趟排序是否进行了元素交换,如果这趟没有进行过元素交换,那么数组排序就结束了。
代码实现
/**
* @author :Mrs.You
* @date :2020/10/18 15:14
* @description:冒泡排序
*/
public class BubbleSort {
public static void main(String[] args) {
int[] a = {-2, 5, 4, 6, 1, 2};
System.out.println("排序前数组:"+ Arrays.toString(a));
bubbleSort(a);
}
/**
* 冒泡排序
* i < a.length-1 对于有n个数的数组,要进行n-1趟冒泡
* j < a.length-1-i 每一趟排序比较的次数在递减 第一趟比较n-1次,结束后最后一位已经排好;
* 第二趟比较n-2次,结束后倒数第二位已排好...
* 如果某一趟排序没有进行过元素交换,说明整个数组已经有序,可以结束了
* 优化:使用一个标志位,初始为false,如果该趟比较有进行交换,就置为true;
* 如果该趟结束后标志位仍然是false,就结束循环。
* @param a
*/
private static void bubbleSort(int[] a) {
int temp = 0;
boolean flag = false;
int compare = 0;
int change = 0;
for(int i = 0; i < a.length-1; i++){
flag = false;
compare = 0;
change = 0;
for (int j = 0; j < a.length-1-i; j++){
compare++;
if (a[j] > a[j+1]){
temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
flag = true;
change++;
}
}
System.out.println("第"+(i+1)+"趟排序后:"+Arrays.toString(a)+",共进行"+compare+"次比较,"+change+"次交换");
if (!flag) break;
}
}
}
由结果可以看出,在发现第四趟排序没有进行过元素交换,就提前结束了程序。
-转载请注明出处~