一:基础版本的冒泡排序
冒泡排序的构思
首先我们看上图所示,这是整个冒泡排序的过程。我们先来看进行遍历一次冒泡排序如何去做。
(1)将初始位置的数与下一个数进行比较大小,如果 当前位置的数 > 下一个位置的数,则交换位置,然后++(也就是进行下一个数的比较),如果 当前位置的数 < 下一个位置的数,则直接进行下一个数的操作。一直将最大的数放置最后一位为止,那么一次冒泡排序便完成了。所以到这一步我们可以构思出需要一个for循环来进行遍历,还有一个if语句来进行判断大小并且判断完成之后选择是否交换两个数的位置。
for (int i = 0; i < arr.length-1; i++) {
if (arr[i] > arr[i+1]) {
int temp = arr[i+1];
arr[i+1] = arr[i];
arr[i] =temp;
}
}
而这里需要注意的是遍历的次数为什么是arr.length-1不是arr.length,因为可以看到最后一次比较时我们arr[i]是数组的最大值,那么arr[i+1]就会超出数组的长度,这里会引起报错。然后就是下面的交换位置的代码,注意i是数组下标不是数组数。到这里我们一次冒泡排序就已经完成了。
(2)冒泡排序需要进行多次遍历,所以我们还需要再外套一个for循环来控制趟数。那从上面的动图我们可以看出需要遍历的趟数就是我们数组的大小。
public static int[] BubbleSort(int[] arr) {
for (int j = 0; j < arr.length; j++) {
for (int i = 0; i < arr.length-1; i++) {
if (arr[i] > arr[i+1]) {
int temp = arr[i+1];
arr[i+1] = arr[i];
arr[i] =temp;
}
}
}
return arr;
}
public static void main(String[] args) {
int[] arr = {3,38,5,44,47,15,36,26,27,2,46,4,19,50,48};
System.out.println(Arrays.toString(BubbleSort(arr)));
}
这里需要注意的点是为什么if的判断条件是arr[i] > arr[i+1]不是 arr[i] >= arr[i+1],这里涉及到排序方法的稳定性,一个排序方法的稳定性取决于当数据中如果有相同的数进行排序之后是否会改变相同数的先后顺序,如果改变了则该排序不稳定,反之不改变位置我们则认为是稳定的排序算法。
二:优化版本的冒泡排序
普通版本的冒泡排序我们可以看到每一趟都需要遍历到最后一位数字,但是我们可以看出当我们第一趟遍历完成之后最后一个数字其实已经有序了不需要再进行比较判断了,而且每一趟遍历都会增加一位有序数字,所以我们每一趟遍历的次数为arr.length-1-0,arr.length-1-1,arr.length-1-2,.......arr.length-1-n。而这里的n的大小不就是我们外部for循环控制的趟数吗也就是j。
public static int[] BubbleSort(int[] arr) {
for (int j = 0; j < arr.length; j++) {
for (int i = 0; i < arr.length-1-j; i++) {
if (arr[i] > arr[i+1]) {
int temp = arr[i+1];
arr[i+1] = arr[i];
arr[i] =temp;
}
}
}
return arr;
}
public static void main(String[] args) {
int[] arr = {5,38,5,44,47,15,36,26,27,2,46,4,19,50,48};
System.out.println(Arrays.toString(BubbleSort(arr)));
}
三:二次优化的冒泡排序
那除了上述的优化以外,还有一个地方可以优化。假设初始数组为 [1, 2, 3, 4, 5]
,这是一个已经有序的数组。第一轮比较:比较 (1, 2)
、(2, 3)
、(3, 4)
、(4, 5)
,没有发生交换,直接结束排序。
public static int[] BubbleSort(int[] arr) {
boolean flag = false;
for (int j = 0; j < arr.length; j++) {
for (int i = 0; i < arr.length-1-j; i++) {
if (arr[i] > arr[i+1]) {
int temp = arr[i+1];
arr[i+1] = arr[i];
arr[i] =temp;
flag = true;
}
}
if (flag == false) {
break;
} else {
flag = false;
}
}
return arr;
}
public static void main(String[] args) {
int[] arr = {5,38,5,44,47,15,36,26,27,2,46,4,19,50,48};
System.out.println(Arrays.toString(BubbleSort(arr)));
}
冒泡排序的最坏时间复杂度为O(n2),因为最外层for循环为n-1,内部外n-1-j,所以算法就是(n-1)+(n-2)+(n-3)+....1。空间复杂度为O(1),因为只创建了一个临时变量temp的额外空间,前面也说了,冒泡排序是一个稳定的排序方法(人为可以做到稳定的排序算法就是稳定的排序算法)。