冒泡排序是排序算法中,容易理解且简单的一种算法
主要思路如下:
-
依次比较数组中相邻两个元素大小,若 a[j] > a[j+1],则交换两个元素,两两都比较一遍称为一轮冒泡,结果是让最大的元素排至最后
-
重复以上步骤,直到整个数组有序
1.基本实现
在每一轮遍历中,相邻两个数据进行比较,当左边比右边大时,两者交换位置。每一轮完成后,都会有一个最大的值放在最后。循环结束后数组即排序完成。
public static void bubble(int[] a) {
for (int j = 0; j < a.length - 1; j++) {
// 一轮冒泡
for (int i = 0; i < a.length - 1; i++) {
System.out.println("比较次数" + i);
if (a[i] > a[i + 1]) {
//交换位置
Utils.swap(a, i, i + 1);
swapped = true;
}
}
System.out.println("第" + j + "轮冒泡"
+ Arrays.toString(a));
}
}
2.优化1
在内层循环中我们发现,循环的次数是从头遍历比较到尾,但是其实在前面的循环中,我们数组后边的数据其实是已经排好序了。比如我们在第一次循环中,会将数组中的最大的数放在数组最后一个位置。在第二次循环中,将数组中第二大的数放在倒数第二个位置。以此类推,其实数组末尾的数随着循环排序的进行,是已经有序的,所以末尾的数据比较是没有必要的。
所以修改内层循环的循环次数
public static void bubble(int[] a) {
for (int j = 0; j < a.length - 1; j++) {
// 一轮冒泡 //优化比较次数
for (int i = 0; i < a.length - 1 - j; i++) {
System.out.println("比较次数" + i);
if (a[i] > a[i + 1]) {
//交换位置
Utils.swap(a, i, i + 1);
swapped = true;
}
}
System.out.println("第" + j + "轮冒泡"
+ Arrays.toString(a));
}
}
3.优化2
在某些情况下,其实我们的数组,在总体循环完成之前,就已经有序了。所以在有序之后的操作其实是没必要的。我们可以优化这里的代码。设置一个标志位,检查一轮循环中是否发生了交换,如果没有即数组有序。
public static void bubble(int[] a) {
for (int j = 0; j < a.length - 1; j++) {
// 一轮冒泡
boolean swapped = false; // 是否发生了交换
for (int i = 0; i < a.length - 1 - j; i++) {
System.out.println("比较次数" + i);
if (a[i] > a[i + 1]) {
Utils.swap(a, i, i + 1);
swapped = true;
}
}
System.out.println("第" + j + "轮冒泡"
+ Arrays.toString(a));
if (!swapped) {
break;
}
}
}
4.最终优化(拓展
通过记录每一轮循环,最后发生交换的位置,减少下一轮比较的个数(在特殊情况下有用,一般使用优化2版就可以了,可以当作拓展
public static void bubble_v2(int[] a) {
int n = a.length - 1;
while (true) {
int last = 0; // 表示最后一次交换索引位置
for (int i = 0; i < n; i++) {
System.out.println("比较次数" + i);
if (a[i] > a[i + 1]) {
Utils.swap(a, i, i + 1);
last = i;
}
}
n = last;
System.out.println("第轮冒泡"
+ Arrays.toString(a));
if (n == 0) {
break;
}
}
}