今天下午笔者在网上查阅算法时,无意间发现了一个算法,名曰“鸡尾酒排序”。啥?没听过啊,点击去一看,该算法是冒泡排序算法的一种改进。在每一次循环的时候,从当前剩下未排序的数组里选择最小值放在数组前面,最大值放在数组后面(这里的前面与后面指的是在未排序部分)。因此,该算法本身外层迭代次数为数组长度的一半。
例如,对于原始数组
14, 12, 18, 12, 1, 6, 18, 4, 0, 2, 0
第一次迭代后,原数组变更为
0, 12, 14, 12, 1, 6, 18, 4, 0, 2, 18
即将最小值0和最大值18分别存放于数组首和数组尾。第二次迭代后,原数组变更为
0, 0, 12, 12, 1, 6, 14, 4, 2, 18, 18
第三次迭代后,数组变更为
0, 0, 1, 12, 2, 6, 12, 4, 14, 18, 18
由此可见,排序结果在预期之内。值得注意的是,这个算法虽然在外层循环的时候,其循环次数为数组长度的一半,但是内层包含两个循环,其最坏情况下的复杂度为O(n^2)。但是若数组本身大部分内容已经有序,则迭代次数接近于O(n)。
代码如下:
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Random;
/**
* This class, {@code BidirectionalBubbleSort} is another version of
* {@link org.vimist.pro.Algorithm.Sort.BubbleSort} and it's an illustration
* of that algorithm.
*
* @author Mr.K
*/
public class BidirectionalBubbleSort {
public static void main(String[] args) {
int N = 15;
int[] numbers = new int[N];
Random random = new Random();
for (int i = 0; i < N; i++) {
numbers[i] = random.nextInt(2 * N);
}
System.out.println("待排序数组: " + Arrays.toString(numbers) + "\n");
bidirectionalBubbleSort(numbers);
System.out.println("\n已排序数组: " + Arrays.toString(numbers));
}
/**
* Another version of {@link org.vimist.pro.Algorithm.Sort.BubbleSort#bubbleSort(int[])}, which
* starts the sort bidirectionally. Thus the count of iteration is half of the length of specified
* array.
* <ul>
* <li>In each iteration, there exists two <em>For-Loops</em>. For the i-th iteration, the
* i-th minimum number will be put in the front of the specified array, and the i-th maximum
* number will be put in the back of specified array.</li>
* </ul>
* Be aware that the cost of time for this algorithm is O(n^2) in some worst cases. If most part of
* the array is sorted, then the cost of time converge to O(n).
*
* @param arr specified array to be sorted
*/
public static void bidirectionalBubbleSort(@NotNull int[] arr) {
for (int i = 0; i < arr.length / 2; i++) {
/**
* Puts the minimum numbers to the front of specified array.
*/
for (int j = arr.length - i - 1; j > i; j--) {
if (arr[j - 1] > arr[j]) {
int temp = arr[j - 1] ^ arr[j];
arr[j - 1] = temp ^ arr[j - 1];
arr[j] = temp ^ arr[j];
}
}
/**
* Puts the maximum numbers to the back of specified array.
*/
for (int j = i; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j] ^ arr[j + 1];
arr[j] = temp ^ arr[j];
arr[j + 1] = temp ^ arr[j + 1];
}
}
System.out.println("第" + String.format("%2d", i + 1) + "次迭代后: " + Arrays.toString(arr));
}
}
}
运行结果如下:
待排序数组: [6, 27, 15, 21, 11, 15, 26, 16, 10, 6, 15, 22, 6, 24, 22]
第 1次迭代后: [6, 6, 15, 21, 11, 15, 26, 16, 10, 6, 15, 22, 22, 24, 27]
第 2次迭代后: [6, 6, 6, 15, 11, 15, 21, 16, 10, 15, 22, 22, 24, 26, 27]
第 3次迭代后: [6, 6, 6, 10, 11, 15, 15, 16, 15, 21, 22, 22, 24, 26, 27]
第 4次迭代后: [6, 6, 6, 10, 11, 15, 15, 15, 16, 21, 22, 22, 24, 26, 27]
第 5次迭代后: [6, 6, 6, 10, 11, 15, 15, 15, 16, 21, 22, 22, 24, 26, 27]
第 6次迭代后: [6, 6, 6, 10, 11, 15, 15, 15, 16, 21, 22, 22, 24, 26, 27]
第 7次迭代后: [6, 6, 6, 10, 11, 15, 15, 15, 16, 21, 22, 22, 24, 26, 27]
已排序数组: [6, 6, 6, 10, 11, 15, 15, 15, 16, 21, 22, 22, 24, 26, 27]