给自己五分钟,彻底搞懂并优化冒泡排序
冒泡排序思想
给定一个无序数组,让“重”的元素下沉,轻的元素上浮”,这个就是冒泡排序。
算法描述
1. 对于给定长度为N的数组, 我们从头进行N次扫描。
2. 每一次扫描相邻的两个元素进行大小比较,若某一元素大于它的下一个元素,就进行交换。
3. 每一次扫描都会把剩余元素的最大值下沉到剩余元素的末尾。故每扫描一次,下一次扫描的超度相应的就减一。
示例
假设要对 下面数组进行排序:
{5, 4, 12, 11, 19, 2, 1, 14}
第 1 趟扫描排序: 4 和 5 交换,12 和 11 交换, 19 下沉到数组末尾。
{4, 5, 11, 12, 2, 1, 14, 19}
第 2 趟扫描排序: 12 下沉到剩余元素末尾
{4, 5, 11, 2, 1, 12, 14, 19}
第 3 趟扫描排序: 11 下沉到剩余元素末尾
{4, 5, 2, 1, 11, 12, 14, 19}
第 4 趟扫描排序: 5 下沉到剩余元素末尾
{4, 2, 1, 5, 11, 12, 14, 19}
第 5 趟扫描排序: 4 下沉到剩余元素末尾
{2, 1, 4, 5, 11, 12, 14, 19}
第 6 趟扫描排序: 2 下沉到剩余元素末尾
{1, 2, 4, 5, 11, 12, 14, 19}
第 7 趟扫描排序: 空扫描,并没有元素交换
{1, 2, 4, 5, 11, 12, 14, 19}
冒泡排序的Java代码实现
public static void bubbleSort(int[] arr) {
int temp;
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j + 1] < arr[j]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
冒泡排序的第一次优化
冒泡排序弊端
从上面的结果中我们能看出。
上面的算法实现有弊端,假设我给定一个有序数组进行冒泡排序,这个算法还是会给我排序 N -1趟,每一趟都进行空扫描。
那么有木有方法让元素已经排序好了,没有交换就不进行扫描,直接结束排序呢?
有的。只要在上面算法中动一点小手脚就好。
关键点:只要没有发生元素交换。就直接结束循环扫描。
冒泡排序第一版优化
/**
* 冒泡排序优化 1
* @param arr 数组
*/
public static void bubbleSortPro1(int[] arr) {
int temp;
// 记录每一趟排序是不是有元素交换
boolean hasChange;
for (int i = 0; i < arr.length - 1; i++) {
hasChange = false;
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j + 1] < arr[j]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
// 如果有元素交换就记录下来
hasChange = true;
}
}
// 只要某一趟排序完了没有元素交换,那么就结束。
if (!hasChange) {
break;
}
}
}
冒泡排序第二次优化
假设有下面一个数组
{3, 4, 2, 1, 5, 6, 7, 8}
第一次扫描:
{3 ,2, 1, 4, 5, 6, 7, 8 }
第二次扫描:
{2 ,1, 3, 4, 5, 6, 7, 8 }
第三次扫描:
{1, 2, 3, 4, 5, 6, 7, 8 }
有木有发现一个问题,其实未排序的5,6,7,8(右侧已经有序),但是就算通过第二版优化,减少了扫描次数,那么每一套扫面描还是会让相邻的两个元素进行比较。
那么优化方案是啥:
关键点:记住最后一次交换的位置。下一次扫描只比较到这个位置。往后的元素不再比较。
冒泡排序第二版优化
/**
* 冒泡排序优化版2
*
* @param arr 数组
*/
public static void bubbleSortPro2(int[] arr) {
int tmp;
boolean haschange;
int sortBorder = arr.length - 1;
int lastChangeIndex = 0;
for (int i = 0; i < arr.length - 1; i++) {
haschange = false;
for (int j = 0; j < sortBorder; j++) {
if (arr[j] > arr[j + 1]) {
tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
haschange = true;
lastChangeIndex = j;
}
}
sortBorder = lastChangeIndex;
if (!haschange) {
break;
}
}
}