一、简介
冒泡排序[buble sort]:在喝汽水时,常常会看到许多小气泡飘到上面,这时由于小气泡中的二氧化碳比水轻,而冒泡排序同这个物理现象一样,排序的元素会按照大小想气泡一样一个个向一个方向移动,
Speak in a figure
下面看一个例子:给出如下一组元素,要求按照从小到大的顺序将元素排序:
首先,第一轮:从头到尾按照顺序比较相邻的两个元素,如果发现左边的元素大于右边的元素,则左右元素交换,否则继续进行下一个判断,最终通过第一轮,将最大的数字9排序完成,
第二轮:从第一个位置到倒数第二个元素,按照与第一轮相同的方式进行比较排序,将最大的8确定
其他轮按照相同的流程进行排序,总体的流程图如下图所示:
二、代码
第一版
//冒泡排序V1
public static void sortV1(int[] input) {
//排序轮次,需要排数组长度相同的轮
for (int i = 0; i < input.length - 1; i++) {
//每轮需要对每两个相邻的元素进行比较,每次确定一个元素,所以最大的要-i
for (int j = 0; j < input.length - 1 - i; j++) {
if (input[j] > input[j + 1]) {
//交换左右的值
int tmp = input[j + 1];
input[j + 1] = input[j];
input[j] = tmp;
}//否则不作任何处理
}
}
}
第二版(优化前部分如果已经排序)
这里举一个极端的例子,如果前面的元素都已经是排序的,则无需进行后期轮的循环判断,对最后的两个元素进行交换之后可以直接进行跳出。
public static void sortV2(int[] input) {
for (int i = 0; i < input.length - 1; i++) {
//设置一个标签,如果在该标签内没有交换的元素,证明前面的元素都已经排好序了
boolean flag = true;
//每轮需要对每两个相邻的元素进行比较,每次确定一个元素,所以最大的要-i
for (int j = 0; j < input.length - 1 - i; j++) {
if (input[j] > input[j + 1]) {
//交换左右的值
int tmp = input[j + 1];
input[j + 1] = input[j];
input[j] = tmp;
flag = false;
}//否则不作任何处理
}
//由于本轮没有交换的元素,证明本轮及本轮之后的元素都已经是排好序的,直接跳出
if (flag) break;
}
}
第三版(优化后部分如果已经排序)
如果是这种情况,则第二轮之后无需对后部分无需进行在判断
public static void sortV3(int[] input) {
//lastPoint和savePoint作为内循环的结尾的地方,即:在这之后我都已经排序好了,不要对我循环了,
int lastPoint = input.length - 1;
int savePoint = lastPoint;
for (int i = 0; i < input.length - 1; i++) {
//设置一个标签,如果在该标签内没有交换的元素,证明前面的元素都已经排好序了
boolean flag = true;
for (int j = 0; j < savePoint; j++) {
if (input[j] > input[j + 1]) {
int tmp = input[j + 1];
input[j + 1] = input[j];
input[j] = tmp;
flag = false;
lastPoint = j;
}//否则不作任何处理
}
//保存一下最后的位置
savePoint = lastPoint;
//由于本轮没有交换的元素,证明本轮及本轮之后的元素都已经是排好序的,直接跳出
if (flag) break;
}
}
此外,对于冒泡排序还有其他特殊的情况,例如鸡尾酒排序,由于冒泡排序时间复杂度较高O(n²),此处不再详细展开了,