猴子排序算法

乌洛波罗斯(衔尾蛇)

不知道你有没有见过这个图案

图-衔尾蛇

这是”衔尾蛇”,许多古老的民族都有关于它的神话,柏拉图形容其为“一头在自我吞食状态的宇宙始祖生物“,衔尾蛇是”不死之身”,且“拥有完美的生物结构”。千百年来,衔尾蛇被赋予了数不清的意义,其中就包括较易理解的“循环”,“无限”,以及偏向神学概念的“生死循环”与“轮回”,还有现代科学意义上的“熵增”,甚至惊天动地的“宇宙真理”。

图-圆环之理

按照热力学第二定律,时间的前进是一种熵增的过程,如果宇宙是一个封闭的空间,那么随着时间的推移,“熵”,即混乱度会随着时间的推进而增大。就比如随着时间的进行,伽利略卫星可能破碎然后变成杂乱的木星环…

宇宙的未来似乎就是这样了,即所谓“热寂”,“故事的结局不是火,而是冰。”

但衔尾蛇为我们指出了世界的另一种可能——从无序到有序,衔尾蛇头尾循环,它的运行不曾有终点,只要时间足够,衔尾蛇就能回到先前的任一状态。

衔尾蛇

这不是胡话,试想一下,你拿起一瓶矿泉水扔向空中,总有或多或少的时候水瓶会直接立在地上。那么对无数瓶矿泉水进行这样的操作,总有或多或少的机会让所有水瓶经过抛掷后稳稳立在地上,就好像它们从来没被动过。

同样的,如果让10个数字不停的随机变化,经过足够长的时间后,总会有这10个数分别排列成1到10。

由此我们甚至可以粗略地说:如果一件事有可能发生,那么他就一定能发生。

猴子排序算法

这个算法原自埃米尔·博雷尔在1909年出版的《为未来竞争》一书中提到的“无限猴子定理“(又一说为出自安德雷·柯尔莫哥洛夫在1933年出版的《概率论》中的”零一律“)。该定理内容大致为:给一只猴子一台打印机,虽然这只猴子根本不识字,但会乱按,经过一段时间后,在它乱按出来的单词里总能找到一些至少看起来是有意义的部分,比如一两个简短的单词,由此可以推出:只要给它足够长的时间,猴子甚至能完整地写出一本莎士比亚全集。

所以,以无限猴子理论为基础的猴子算法的实质就是…乱排!

没错,就是纯粹的乱弄,只有当瞎猫撞见死耗子了才能排序成功。

下面我们来试着实现以下…

void algorithm(void)
{
    int temp,index,buffer,mark,numbuffer[DATA_AMOUNT];
    srand(time(NULL));
    while(true)
    {
        // 乱序
        for(int i = 0;i < DATA_AMOUNT;i++)
        {
            index = RANDOM(0, DATA_AMOUNT - 1);
            temp = nums[index];
            nums[index] = nums[i];
            nums[i] = temp;
        }

        // 检查
        mark = 0;
        buffer = nums[1];
        for(int i = 0;i < DATA_AMOUNT - 1;i++)
        {
            if(nums[i] > nums[i+1]) mark = 1;
        }
        if(!mark) break;
    }
}

完整代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <limits.h>

#define RANDOM(N,M) (rand() %((M)-(N)+1)+(N))

#define DATA_AMOUNT 10
#define ALGORITHM_NAME "猴子排序"

int nums[DATA_AMOUNT];
void algorithm(void);

int main(void)
{
    for(int i = 0;i < DATA_AMOUNT;i++) nums[i] = RANDOM(0, 1000);

    int start,end;
    start = clock();
    algorithm();
    end = clock();
    printf("algorithm \"%s\" used %f sec to process %d data\n",ALGORITHM_NAME,(float)(end - start)/CLOCKS_PER_SEC,DATA_AMOUNT);

    for(int i = 0;i < DATA_AMOUNT - 1;i++)
    {
        if(nums[i] > nums[i+1])
        {
            puts("FAILED");
            abort();
        }
    }
    puts("PASSED");

    return 0;
}

void algorithm(void)
{
    int temp,index,buffer,mark,numbuffer[DATA_AMOUNT];
    srand(time(NULL));
    while(true)
    {
        // 乱序
        for(int i = 0;i < DATA_AMOUNT;i++)
        {
            index = RANDOM(0, DATA_AMOUNT - 1);
            temp = nums[index];
            nums[index] = nums[i];
            nums[i] = temp;
        }

        // 检查
        mark = 0;
        buffer = nums[1];
        for(int i = 0;i < DATA_AMOUNT - 1;i++)
        {
            if(nums[i] > nums[i+1]) mark = 1;
        }
        if(!mark) break;
    }
}

你别不信,这鬼算法真的能用:
pkE6Y.png

猴子算法的存在意义

如你所见,猴子算法是一种非常看脸的算法,在最理想的条件下,猴子算法甚至能瞬间完成排序。但更多的时候,猴子算法的耗时趋近于无穷大。

猴子算法的意义更多的是理论上的而非应用上,它打破了排序算法时间复杂度的极限,在理想条件下猴子算法的时间复杂度甚至是 O ( 1 ) O(1) O(1),尽管这个常数通常会大得离谱。


参考或引用
[1] https://baike.baidu.com/item/%E8%A1%94%E5%B0%BE%E8%9B%87/2609957
[2] https://baike.baidu.com/item/%E6%97%A0%E9%99%90%E7%8C%B4%E5%AD%90%E5%AE%9A%E7%90%86/2221476
[3] https://baike.baidu.com/item/%E5%9C%86%E7%8E%AF%E4%B9%8B%E7%90%86/2698298
[4] https://zhuanlan.zhihu.com/p/216250712
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值