什么是冒泡排序
定义
冒泡排序(Bubble Sort)顾名思义,就是被排序的元素会像气泡一样冒出来。冒泡排序的思想是:从左往右遍历所有元素,比较相邻的两个元素,将更大的元素放在右边,一轮遍历完成后,最大的元素就会冒出在最右端。按这个思路遍历全部元素,直到某次遍历没有元素交换时(即右边的都比左边的大),则元素排列完成。
对于博主来说,理解并记忆一个算法最好的办法就是把这个算法的思想场景化,这样就算在紧张的情况下或长时间不用的时候,也可以通过这个场景化的记忆来回忆起具体的算法思想,从而写出这段代码
简单的场景记忆
冒泡算法的理解和记忆时最简单的一个应用场景,提到冒泡排序脑子里第一反应肯定就是冒泡。
- 什么是冒泡?冒泡肯定是要冒到最前或者最后,得冒出来才是冒泡。
- 怎么冒泡呢?一个数组,从前往后数,发现前面的数字比后面的大一些,那就把它往后挪一个,数的过程中肯定会遇到最大的数字,它每次都比后面的大,每次都交换到后面一个位置,遍历一轮后,它就在冒出来在最后面的位置了。
- 每轮全部遍历后都会冒出一个无序元素中的最大元素,最多遍历n-1轮后,数组有序。
排序前数组:[11,04,16,10,22,97,19,18,03,16]
第1次遍历后结果为:[04,10,11,16,22,19,18,03,16,97]
第2次遍历后结果为:[04,10,11,16,19,18,03,16,22,97]
第3次遍历后结果为:[04,10,11,16,18,03,16,19,22,97]
第4次遍历后结果为:[04,10,11,16,03,16,18,19,22,97]
第5次遍历后结果为:[04,10,11,03,16,16,18,19,22,97]
第6次遍历后结果为:[04,10,03,11,16,16,18,19,22,97]
第7次遍历后结果为:[04,03,10,11,16,16,18,19,22,97]
第8次遍历后结果为:[03,04,10,11,16,16,18,19,22,97]
第9次遍历后结果为:[03,04,10,11,16,16,18,19,22,97]
第10次遍历后结果为:[03,04,10,11,16,16,18,19,22,97]
ps:此处如果有动图会更便于理解,暂时还不会做动图,先留着
改良思路
改良思路1: 上述例子发现最后两次的遍历是完全没有变化的,在第8次结束后,整个数组已经全部有序,因此可以加个flag来标示,当本次遍历没有任何交换时,则整个数组全部有序,不需要进行后续的遍历。
改良思路2: 每轮遍历后,交换的最后一个位置即为后面有序数组的开始,下轮遍历时,便不需要再次遍历这些有序数组。
算法特性
- 时间复杂度为:O(n2),最差的情况为数组倒序:O(n2),最好的情况为数组正序:O(n);
- 空间复杂度为:O(1);
- 是一种稳定的排序算法(不改变排序前两个相同元素的位置)
为什么要学习冒泡排序
作为比较简单以及常用的几种排序之一,在入门学习数据结构和算法时,常常用来做入门的引导,且冒泡排序的思路可以做很多扩展,变形为其他的改良后的排序,如上面的两种简单的改良思路。
代码实现
java版代码实现
改良思路1:
public int[] sort(int[] sortArray) {
// 代码健壮性
if (sortArray == null) {
return null;
}
// 边界case
if (sortArray.length <= 1) {
return sortArray;
}
// 不改变输入值,也可以直接在原数组上操作,根据需要自己选择
int[] copyArr = Arrays.copyOf(sortArray, sortArray.length);
for (int i = 1; i < copyArr.length; i++) {
boolean flag = true;
for (int j = 0; j < copyArr.length - 1; j++) {
if (copyArr[j] > copyArr[j + 1]) {
int middle = copyArr[j];
copyArr[j] = copyArr[j + 1];
copyArr[j + 1] = middle;
flag = false;
}
}
if (flag) {
return copyArr;
}
}
return copyArr;
}
改良思路1+2:
public int[] sort(int[] sortArray) {
// 代码健壮性
if (sortArray == null) {
return null;
}
// 边界case
if (sortArray.length <= 1) {
return sortArray;
}
// 不改变输入值,也可以直接在原数组上操作,根据需要自己选择
int[] copyArr = Arrays.copyOf(sortArray, sortArray.length);
int orderedStart = copyArr.length - 1;
int orderedFlag = copyArr.length - 1;
for (int i = 1; i < copyArr.length; i++) {
boolean flag = true;
for (int j = 0; j < orderedStart; j++) {
if (copyArr[j] > copyArr[j + 1]) {
int middle = copyArr[j];
copyArr[j] = copyArr[j + 1];
copyArr[j + 1] = middle;
flag = false;
orderedFlag = j;
}
}
orderedStart = orderedFlag;
if (flag) {
return copyArr;
}
}
return copyArr;
}