算法沙雕排序算法之猴子排序、睡眠排序
蔡坨坨转载请注明出处❤️
作者:测试蔡坨坨
原文链接:caituotuo.top/1b3dc548.html
你好,我是测试蔡坨坨。
当谈到算法时,通常人们会追求最优解,而最优解的评判标准主要考虑时间复杂度和空间复杂度,因为较低的复杂度通常代表着更优秀的算法。然而,有一些有趣的例外,即那些非传统的算法,如猴子排序(Monkey Sort)和睡眠排序(Sleep Sort),都是一些令人忍俊不禁的例子,尽管它们并不实用,但它们都引发了人们的兴趣和好奇心。
本篇将详细探讨这两种算法。
猴子排序算法
在一本1909年出版谈概率的书籍中,埃米尔·博雷尔提出了无限猴子定理,其中介绍了“打字的猴子”的概念。
故事情节
很久以前,有一个猴子叫做查尔斯,他生活在一个巨大的图书馆里。这个图书馆里有数以亿计的书籍和打字机,包含了所有可能的字母、数字和标点符号。查尔斯对打字机产生了浓厚的兴趣。
有一天,查尔斯突然站在了一台打字机前。虽然他并不知道如何打字,但他开始随机地按下键盘上的键。他的动作毫无规律,就像是瞎猜一样。
人们会好奇地想知道,如果查尔斯一直随机地按键,是否有一天他能够打出莎士比亚的某一部作品,比如《哈姆雷特》呢?或者打出一本完整的百科全书?
这个故事用来探讨概率和无序事件的概念。理论上,查尔斯确实有可能在某一刻随机地按键,打出一部文学作品或其他文字。然而,由于随机性极高,要实现这一点所需要的时间几乎是不可想象的。这个思考实验强调了概率事件的稀有性和随机性,以及在实际情况下,某些事件可能需要极长的时间才能发生。
真猴子实验
为了验证这一理论的真实性,2003年,英国一所大学的师生从学校里拿了两千欧元的科研经费,给动物园的猴子买了一台电脑和一个键盘。然而结果并不尽人意,在一个月的相处时间里,猴子除了胡乱敲键盘外,剩下的时间便是在电脑上进行大小便,最终导致电脑无法正常运行,实验宣告失败。
程序模拟猴子敲键盘
后来有人尝试用计算机程序来模拟猴子敲击键盘,最终在花费了 421625*10^23 年后,终于打出了莎士比亚的前十九个字母VALENTINE.Cease to。
猴子排序算法
基于上述理论,便可以得到猴子排序算法,也被称为猴子补丁排序(BogoSort)。对于要排序的数组,每一次给它进行一个随机的排序,那么总有一次,它能够变成一个有序的数组,如果运气好,可能一次就搞定(一次成功的幸运猴,时间复杂度就是O(N),Perfect!),如果运气不好,可能一直都不会成功(永不成功猴,时间复杂度就是INF)。
Python代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
|
import random import time
def is_sorted(arr): for i in range(1, len(arr)): if arr[i - 1] > arr[i]: return False return True
def monkey_sort(arr): attempts = 0 start_time = time.time()
while not is_sorted(arr): random.shuffle(arr) attempts += 1 print(f'第{attempts}次:' + str(arr))
end_time = time.time() elapsed_time = end_time - start_time
return arr, attempts, elapsed_time
if __name__ == "__main__": input_array = [random.randint(1, 1000) for _ in range(10)]
sorted_array, attempts, elapsed_time = monkey_sort(input_array)
print("原始数组:", input_array) print("排序后的数组:", sorted_array) print("排序尝试次数:", attempts) print("排序耗时(秒):", elapsed_time)
|
我们尝试用猴子排序算法对10个1~1000范围内的数据做排序,看看最终要尝试多少次,花费多长时间?
接下来就是见证奇迹的时刻……
速度也不算太慢,也就尝试了7920246次,耗时448秒,不到8分钟。(笑哭
Java代码实现
基本思路:
将数组打乱:方法1、自己写一个方法;方法2、使用Collections.shuffle()
由于Collections.shuffle(List<?> list)
需接收一个List参数,因此可以使用guava(瓜瓦),Google提供的api Ints.asList(int... backingArray)
将int数组转成list。
1 2 3 4 5 6
| <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>23.0</version> </dependency>
|
判断数组是否按顺序排序
具体代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| package top.caituotuo.sortUtil;
import com.google.common.primitives.Ints;
import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Random;
public class MonkeySort { public static void main(String[] args) { int[] inputArray = new int[10]; Random rand = new Random(); for (int i = 0; i < inputArray.length; i++) { inputArray[i] = rand.nextInt(1000) + 1; }
System.out.println("原始数组: " + Arrays.toString(inputArray)); monkeySort(inputArray); }
public static void monkeySort(int[] nums) { int attempts = 0; long startTime = System.currentTimeMillis(); out: while (true) { List<Integer> tempList = Ints.asList(nums); Collections.shuffle(tempList); int[] result = Ints.toArray(tempList);
for (int i = 1; i < result.length; i++) { if (result[i - 1] > result[i]) { attempts++; System.out.printf("第%s次: %s%n", attempts, Arrays.toString(result)); continue out; } }
attempts++; System.out.printf("第%s次: %s%n", attempts, Arrays.toString(result));
System.arraycopy(result, 0, nums, 0, result.length); break; }
long endTime = System.currentTimeMillis(); double elapsedTime = (endTime - startTime) / 1000.0;
System.out.println("排序后的数组: " + Arrays.toString(nums)); System.out.println("排序尝试次数: " + attempts); System.out.println("排序耗时(秒): " + elapsedTime); } }
|
测试结果:
睡眠排序算法
聊完猴子排序,我们再来看看睡眠排序。
睡眠排序算法是一个奇特而有趣的概念,其做法就是根据数字数组创建多个线程,并使每个线程休眠的时间与其对应的数字值成正比,数值越小的线程就会越早醒来,数值越大的线程就会越晚醒来,这样就完成了对数据的排序。
听起来是不是很有趣,但实际上,睡眠排序面临许多问题,包括线程创建和管理的开销,以及对于小数值和相同数值的处理。因此,它实际上并不是一个可行的排序算法,而是一种有趣的编程挑战和思考实验。
Python代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
|
import random import threading import time
def sleep_sort(nums): sorted_array = []
def sleep_and_append(num): time.sleep(num) sorted_array.append(num)
start_time = time.time()
threads = [] for num in nums: thread = threading.Thread(target=sleep_and_append, args=(num,)) threads.append(thread) thread.start()
for thread in threads: thread.join()
print("排序后的数组:", sorted_array) print("排序耗时(秒):", time.time() - start_time)
if __name__ == "__main__": input_array = [random.randint(1, 10) for _ in range(5)] print("原始数组:", input_array) sleep_sort(input_array)
|
运行结果:
从运行结果可以看出,睡眠排序的耗时取决于数组中最大的那个数字,数字越大,耗时越久;当数组中存在负数时,运行就会报错,因为线程的睡眠时间不能为负数。
Java代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| package top.caituotuo.sortUtil;
import java.util.Arrays; import java.util.Random;
public class SleepSort { public static void sleepSortAndPrint(final int[] nums) { final int[] sortedArray = new int[nums.length]; final int[] index = {0};
long startTime = System.currentTimeMillis();
for (int num : nums) { new Thread(() -> { try { Thread.sleep(num); sortedArray[index[0]++] = num; } catch (InterruptedException e) { e.printStackTrace(); } }).start(); }
while (index[0] < nums.length) { try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } }
long endTime = System.currentTimeMillis(); double elapsedTime = (endTime - startTime) / 1000.0;
System.out.println("排序后的数组: " + Arrays.toString(sortedArray)); System.out.println("排序耗时(秒): " + elapsedTime); }
public static void main(String[] args) { int[] inputArray = new int[10]; Random rand = new Random(); for (int i = 0; i < inputArray.length; i++) { inputArray[i] = rand.nextInt(100) + 1; } System.out.println("原始数组: " + Arrays.toString(inputArray)); sleepSortAndPrint(inputArray); } }
|
运行结果:
这两种算法在实际应用中并不常见,但它们以其独特的方式引发了人们的兴趣。猴子排序算法可能是一种“乱序”数据的有趣方式,而睡眠排序算法则是一种富有创意的尝试,尽管并不实际可行。这些算法的目的通常不是为了优化时间或空间复杂度,而是为了娱乐或启发思考。
因此,虽然大多数情况下我们关注最优化算法,但也有一些算法,如猴子排序和睡眠排序,它们不追求传统的效率标准,而是为了不同的目的而存在,让人们在计算领域保持创意和幽默的一面。
你还了解其他有趣的算法吗?欢迎分享并进行探讨。