对于一个数组[4, 6, 3, 9]而言:
首先进行第一轮:
第一次比较:4<6 所以不用交换两元素 数组不变为[4, 6, 3, 9]
第二次比较:6>3 所以交换两元素 得到一个新数组为[4, 3, 6, 9]
第三次比较:6<9 所以不用交换两元素 数组不变为[4, 3, 6, 9]
第一轮完成 确定一个数归位 即9
然后进行第二轮:
第一次比较:4>3 所以交换两元素 得到一个新数组为[3, 4, 6, 9]
第二次比较:4<6 所以不用交换两元素 数组不变为[3, 4, 6, 9]
第二轮完成 确定一个数归位 即6
然后进行第三轮:
第一次比较:3<4 所以不用交换两元素 数组不变为[3, 4, 6, 9]
第三轮完成 确定一个数归位 即4
最后将原数组升序排序 得到新数组[3, 4, 6, 9]
结论:前提条件总轮数是从1开始计数的:
总轮数 = 元素总个数 - 1
当前轮数(i)对应的总比较次数 = 元素总个数 - i
但是循环中一般都是从0开始计数的 所以规律应该是以下这样子的:
总轮数 = 元素总个数 - 1
当前轮数(i)对应的总比较次数 = 元素总个数 - i - 1
下面是冒泡排序的图解过程:
冒泡排序图解.xmind
接着是冒泡排序的代码实现:
// 这一个版本是冒泡排序的初始版本
public class BubbleSort{
// 定义一个主函数 用于调用冒泡排序函数
public static void main(String[] args){
// 定义一个int类型数组
int[] arr = {4, 6, 3, 9};
// 打印排序前的数组
System.out.println(Arrays.toString(arr));
// 调用冒泡排序函数对数组进行排序
bubbleSort(arr);
// 打印排序后的数组
System.out.println(Arrays.toString(arr));
}
// 定义一个函数 用于对无序数组进行冒泡排序 使其升序排序 接收一个参数 即目标数组
public static void bubbleSort(int[] arr){
// 定义两层循环 外层循环表示的是轮数 内层循环表示的是比较次数
for(int i = 0; i < arr.length - 1; i++){
for(int j = 0; j < arr.length - i - 1; j++){
// 当相对靠前的数大于相对靠后的数时 交换两个数
if(arr[j] > arr[j + 1]){
// 下列过程为两数交换的过程
// 定义一个临时变量 用于储存相对靠前的数
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
}
但是其实这个排序方法存在两个优化的地方:
1.如果数组还未进行到最后一步就已经完成排序的话 那么其实不需要再继续进行下去了
2.如果冒泡排序某个阶段的数组是由前一部分的无序部分和后一部分的有序部分组成的 那么排序范围应该是针对前一部分的这个无序部分 而不是整个部分
3.其实上述的代码没有指定特殊情况的处理机制
针对上述这三个需要优化的地方,我们重新优化后的代码如下所示
// 这一个版本是冒泡排序的优化版本
public class BubbleSortOptimization{
// 定义一个主函数 用于调用冒泡排序函数
public static void main(String[] args){
// 定义一个int类型数组
int[] arr = {4, 6, 3, 9};
// 打印排序前的数组
System.out.println(Arrays.toString(arr));
// 调用冒泡排序函数对数组进行排序
bubbleSort(arr);
// 打印排序后的数组
System.out.println(Arrays.toString(arr));
}
// 定义一个函数 用于对无序数组进行冒泡排序 使其升序排序 接收一个参数 即目标数组
public static void bubbleSort(int[] arr){
// 定义一个变量 用于记录无序部分和有序部分的边界 初始值为arr.length-0-1 即arr.length-1
int sortBorder = arr.length - 1;
// 定义一个变量 用于记录最后进行交换的元素中的相对靠前元素的下标 初始值为0
int lastExchangeIndex = 0;
// 针对特殊情况 以下是处理机制
if(arr == null || arr.length < 2){
return;
}
// 定义两层循环 外层循环表示的是轮数 内层循环表示的是比较次数
for(int i = 0; i < arr.length - 1; i++){
// 定义一个变量 用于判断当前内层循环中是否存在两数交换的情况 初始值为true
boolean isSort = true;
for(int j = 0; j < sortBorder; j++){
// 当相对靠前的数大于相对靠后的数时 交换两个数
if(arr[j] > arr[j + 1]){
// 将isSort赋值为false
isSort = false;
// 下列过程为两数交换的过程
// 定义一个临时变量 用于储存相对靠前的数
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
// 记录以下最后进行交换的元素下标
lastExchangeIndex = j;
}
}
// 当一个内层循环结束后 应该对这个内层循环进行判断 如果这个内层循环不存在两数交换的情况 那么就终止循环
if(isSort){
break;
}
// 当一个内层循环结束后 应该对边界变量重新赋值
sortBorder = lastExchangeIndex;
}
}
}