前言
上节,我们已经通过对冒泡算法的优化、能够达到我们预想的结果。比较次数的减少、本节将继续在冒泡排序的基础上进行优化、能够达到刚好的效果。
鸡尾酒排序
为什么叫鸡尾酒排序呢?可能这个名字起得比较特殊。它是基于冒泡排序做了一些小小的改动。也叫做快乐钟摆排序
现在,大家的脑子里肯定会想到一个古老的钟摆。。。。。
左摇一下、右摇一下、重复不止
现在请记住这个场景。我们来学习一下这个鸡尾酒排序
为何方神圣!
冒泡排序特点
从左往右、依次循环比较、一遍将一个大元素推到最右侧。
鸡尾酒排序特点
- 将原有的单向改为
双向比较
- 每次循环则将
最小
元素和最大
元素分别推至左右两侧
画图理解
准备一个数组 [49, 38, 65, 97, 76, 13, 27, 49]
钟摆循环1开始 从右至左
我们发现,这个最小的元素13
已经被确认出来了。
钟摆循环2开始 从左至右
代码示例
public static void sort4(int[] array) {
int temp = 0;
int allChange = 0;
/**
* 外层循环用于控制程序总体循环次数
*/
for (int i = 0; i < array.length / 2; i++) {
/**
* 有无交换元素标记
*/
boolean isChange = true;
//从左向右摆动
for (int j = i; j < array.length - i - 1; j++) {
if (array[j] > array[j + 1]) {
//交换元素
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
isChange = false;
}
allChange++;
}
if (isChange) break;
isChange = true;
//从右向左摆动
for (int g = array.length - i - 1; g > i; g--) {
if (array[g] < array[g - 1]) {
temp = array[g];
array[g] = array[g-1];
array[g-1] = temp;
isChange = false;
}
allChange++;
}
if (isChange) break;
}
System.out.println(Arrays.toString(array));
System.out.println("总体比较次数:"+allChange);
}
结果如下:
[13, 27, 38, 49, 49, 65, 76, 97]
总体比较次数:30
通过观察我们发现,当前算法的比较次数还是相对来说较多的。外层大循环运行减少一半、但是内层两个小循环还是需要注意的。有什么办法可以优化一下呢?我们可以采用之前的思路。通过设置有序长度
的方式来减少内层循环次数、已达到我们优化的目的。
有序优化
其实说白了,就是在发生变化的时候记录当前位置,下次循环到本次记录的位置停止则可以了。
通过两个边界变量leftBorder
与rightBorder
控制程序比较位置的终止。
左循环从左边界比较到右边界停止
右循环从右边界比较到左边界停止
public static void sort5(int[] array) {
int temp = 0;
int allChange = 0;
//记录左边界
int leftBorder = 0;
//右边界
int rightBorder = array.length - 1;
//左边发生变化的位置
int leftChangeIndex = 0;
//右边发生变化的位置
int rightChangeIndex = 0;
/**
* 外层循环用于控制程序总体循环次数
*/
for (int i = 0; i < array.length / 2; i++) {
/**
* 有无交换元素标记
*/
boolean isChange = true;
//从左向右摆动
for (int j = leftBorder; j < rightBorder; j++) {
if (array[j] > array[j + 1]) {
//交换元素
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
isChange = false;
//记录右边边界
rightChangeIndex = j;
}
allChange++;
}
//用于下次循环终止
rightBorder = rightChangeIndex;
if (isChange) break;
isChange = true;
//从右向左摆动
for (int g = rightBorder; g > leftBorder; g--) {
if (array[g] < array[g - 1]) {
temp = array[g];
array[g] = array[g-1];
array[g-1] = temp;
isChange = false;
//记录左边界
leftChangeIndex = g;
}
allChange++;
}
leftBorder = leftChangeIndex;
if (isChange) break;
}
System.out.println(Arrays.toString(array));
System.out.println("总体比较次数:"+allChange);
}
--------------
[13, 27, 38, 49, 49, 65, 76, 97]
总体比较次数:27
小结
至此我们已经学习了有关的三个排序方式、包括最基础的冒泡排序、优化冒泡排序。最终的冒泡排序。通过钟摆思想实现的鸡尾酒排序法。越来觉得一个小小的排序,通过学习后发现,竟然有很多有意思的地方。
参考
https://mp.weixin.qq.com/s/CoVZrvis6BnxBQgQrdc5kA