猴子排序(Bogo Sort)是一种幽默的排序算法,其名称来源于"无限猴子定理"——如果一只猴子在打字机上随机按键,最终会打出莎士比亚全集。猴子排序也被称为"愚蠢排序"(Stupid Sort)或"随机排序"(Random Sort)。它不是实际使用的排序算法,而是用来演示算法复杂度分析的反面教材。
猴子排序的算法极其简单:
import java.util.Random;
public class BogoSort {
/**
* 猴子排序
* 警告:此算法平均时间复杂度为 O((n+1)!),仅用于教学演示
* 对于超过 10 个元素的数组,可能需要数小时甚至数天才能完成排序
*/
public static void sort(int[] arr) {
Random random = new Random();
int attempts = 0;
while (!isSorted(arr)) {
shuffle(arr, random);
attempts++;
// 安全保护,避免无限循环
if (attempts > 1_000_000) {
System.out.println("超过一百万次尝试,放弃排序");
return;
}
}
System.out.println("排序完成,共尝试 " + attempts + " 次");
}
/**
* 检查数组是否有序
*/
private static boolean isSorted(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i] > arr[i + 1]) {
return false;
}
}
return true;
}
/**
* Fisher-Yates 洗牌算法
*/
private static void shuffle(int[] arr, Random random) {
for (int i = arr.length - 1; i > 0; i--) {
int j = random.nextInt(i + 1);
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
/**
* 猴子排序(泛型版本)
*/
public static <T extends Comparable<T>> void sortGeneric(T[] arr) {
Random random = new Random();
int attempts = 0;
while (!isSortedGeneric(arr)) {
shuffleGeneric(arr, random);
attempts++;
if (attempts > 1_000_000) {
System.out.println("超过一百万次尝试,放弃排序");
return;
}
}
System.out.println("排序完成,共尝试 " + attempts + " 次");
}
private static <T extends Comparable<T>> boolean isSortedGeneric(T[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i].compareTo(arr[i + 1]) > 0) {
return false;
}
}
return true;
}
private static <T> void shuffleGeneric(T[] arr, Random random) {
for (int i = arr.length - 1; i > 0; i--) {
int j = random.nextInt(i + 1);
T temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
| 指标 | 最好情况 | 最坏情况 | 平均情况 |
|---|---|---|---|
| 时间复杂度 | O(n)(运气极好) | 无界(可能永远不结束) | O((n+1)!) |
| 空间复杂度 | O(1) | O(1) | O(1) |
| 比较次数 | n-1 | 无界 | n(n+1)! |
| 交换次数 | 0 | 无界 | n(n+1)! |
猴子排序是不稳定的排序算法,平均时间复杂度为 O((n+1)!)。对于 10 个元素的数组,平均需要约 4000 万次尝试。它是算法复杂度分析中最经典的反例。