有没有比Bogosort(aka Monkey Sort)更糟糕的排序算法?[关闭]


178

我的同事带我回到了大学时代,今天早上讨论了排序算法。我们回想起了我们最喜欢的StupidSort,例如其中之一,我们确定我们看到了一种排序算法,该算法是O(n!)。那使我开始寻找可以找到的“最差”的排序算法。

我们假设,一个完全随机排序将是非常糟糕的(即随机化的元素- ?是为了不随机化再次),我环顾四周,发现了它显然称BOGO排序,或猴排序,或者有时只是随机排序

Monkey Sort似乎具有的最差情况性能O(∞),的最佳情况性能O(n)和平均性能O(n·n!)

目前平均可接受的排序性能最差的排序算法是什么(并且蜂声比差O(n·n!))?


10
每个bogosort有多少个bogomips?想问的人想知道。
zombat 2010年

13
为了澄清,您是否排除了最佳情况下性能为O(∞)的平凡情况?
tloflin


6
我听说猴子排序也被称为“醉汉排序”,这个名字让我联想起很多。
Matteo Italia 2010年

6
@Matteo Italia-或称为2岁的任何人都可以证明的“幼儿分类”。
Martin Capodici 2014年

Answers:


442

摘自David Morgan-Mar的 “深奥算法”页面:智能设计排序

介绍

智能设计排序是一种基于智能设计理论的排序算法。

算法说明

原始输入列表按其确切顺序的概率为1 /(n!)。发生这种情况的可能性很小,以至于说这是偶然发生显然是荒谬的,因此它一定是由智能分拣机有意识地按此顺序排列的。因此可以肯定地说,它已经以某种超越了我们对“升序”的天真凡俗的理解的最佳方式进行了排序。任何试图改变秩序以符合我们自己的先入之见的尝试实际上都会使它的分类减少。

分析

该算法在时间上是恒定的,并且对列表进行原位排序,根本不需要额外的内存。实际上,它甚至不需要任何可疑的技术计算机内容。赞美分拣机!

反馈

加里·罗杰斯写道:

使排序时间保持不变会拒绝排序器的功能。排序器存在于时间之外,因此排序是永恒的。需要时间来验证排序会削弱排序器的作用。因此...这种特殊的分类是有缺陷的,不能归因于“分类器”。

异端!


94
也称为“假设排序”:假设列表已排序,请返回!
BioGeek 2010年

42
+100-此答案来自100%的纯胜。
womp'4

11
嘿! 不要忘记“优柔寡断的排序”(也称为“薛定inger的排序”或“量子排序”),列表可以在其中排序,也可以不排序,但是检查列表将显示列表是否排序。这是我的示例实现:void quantum_sort (void *b, size_t n, size_t s, int (*c)(const void *, const void*)) { if (rand () % 2) qsort (b, n, s, c); }
乔D

6
我们应该给这个"This is the best of all posibble worlds because it is the world that is, and so in the best possible world the array would already be sorted!"
候选人

2
首先,我欢迎我们的新排序主管。所有人欢呼分拣机!
布赖森2014年

299

许多年前,我发明了MiracleSort(但从未真正实施过)。

Start with an array in memory.
loop:
    Check to see whether it's sorted.
    Yes? We're done.
    No? Wait a while and check again.
end loop

最终,阿尔法粒子翻转存储芯片中的位将导致排序成功。

为了提高可靠性,请将阵列复制到屏蔽位置,然后对照原始阵列检查可能排序的阵列。

那么,如何对照原始数组检查可能排序的数组?您只需对每个数组进行排序,然后检查它们是否匹配。MiracleSort是用于此步骤的显而易见的算法。

编辑:严格来说,这不是算法,因为不能保证终止。“不是算法”是否可以视为“算法更差”?


39
我假设可以使用宇宙射线来证明该算法的正确性。
ghord 2012年

1
什么是大O? O(2^N)
Mooing Duck 2012年

12
@MooingDuck:我不认为它实际上有一个大O.
基思·汤普森

5
@MooingDuck:严格说来,如果不终止的话,就不是一种算法,这是根据他们在大学和Wikipedia文章中所学到的。
基思·汤普森

7
@Olathe:“暂停问题”说,我们无法为所有程序确定是否暂停,但是有很多程序可供我们确定。我们知道 Quicksort和Bubblesoft停止运行,并且我们知道它们是算法。
基思·汤普森

133

量子Bogosort

假设量子力学的多世界解释是正确的一种排序算法:

  1. 检查列表是否已排序。如果不是,请摧毁宇宙。

在算法结束时,列表将按剩下的唯一Universe排序。该算法需要最坏情况O(N)和平均情况O(1)时间。实际上,执行比较的平均次数为2:在第二个元素上有50%的可能性被销毁,在第三个元素上有25%的可能性被销毁,依此类推。


42
但是,在您刚刚摧毁的宇宙中,时间不再存在。因此,您尚未检查的Universe中的观察者将无法判断已执行了多少算法。因此,由于以前的宇宙破坏不再存在,因此该算法始终需要O(1)时间。
巴里·布朗

12
是的,在唯一观察到该列表已排序的Universe中,执行该过程需要O(n)时间-在其他Universe中花费多长时间是无关紧要的。
尼克·约翰逊

19
然而,该算法具有更大的问题。假设您有100亿次错误地得出结论:如果列表未排序,则会被排序。有20个!排序20个元素列表的方法。排序之后,剩下的Universe将是对列表进行正确排序的Universe,而240万个算法错误地得出了对列表进行正确排序的Universe。因此,您这里拥有的是一种可以大幅放大机器错误率的算法。
尼克·约翰逊,

10
这显然是最好的排序算法,而不是最差的。
Boann 2012年

11
不听从甲虫的建议可能会导致所有宇宙被摧毁。
CrashCodes 2014年

60

我很惊讶还没有人提到sleepsort ...或者我没有注意到它吗?无论如何:

#!/bin/bash
function f() {
    sleep "$1"
    echo "$1"
}
while [ -n "$1" ]
do
    f "$1" &
    shift
done
wait

用法示例:

./sleepsort.sh 5 3 6 3 6 3 1 4 7
./sleepsort.sh 8864569 7

就性能而言,这是可怕的(尤其是第二个示例)。等待近3.5个月来对2个数字进行排序有点不好。


3
似乎是一种O(N)排序,但实际上受操作系统实施计时器的限制。
Mooing Duck 2012年

7
无论如何削减,这可能都比bogosort表现出更好的增长。
Mooing Duck 2012年

8
我在那里看到了比赛情况。

5
您可以更改sleep "$1"sleep "0.$(printf "%010d" $1)"显着提高性能。time ./sleepsort.sh 8864569 7然后在笔记本电脑上以0.009秒的速度运行。
Sam Kellett 2014年

1
这以O(N)复杂度运行(当然取决于计时器的实现),这是一种不同形式的简单存储桶排序。
Qwerty01 2014年


50

我有一位讲师,他曾经建议生成一个随机数组,检查它是否已排序,然后检查数据是否与要排序的数组相同。

最佳情况O(N)(第一次生!)最坏情况O(从不)


4
分析更有趣的是平均情况,这是...?
Mooing Duck 2012年

4
就像所有最好的教科书所说的那样,这留给读者练习!
丹尼尔(Daniel)

40
鸣叫鸭:O(有时)
伊利亚安德O.

1
@MooingDuck然后我们需要知道元素类型的基数和用于在随机数组中生成随机元素的分布。
显示名称

5
复杂度为O(N!* Z ^ N),其中Z是一组可能值的大小,而N是数组的长度。
jakubiszon 2014年

30

如果您以任何方式使算法有意义,O(n!)则可能会达到最差的上限。

由于检查每个可能性以对要排序的集合进行排序会采取n!步骤,因此您不会比这更糟。

如果您要执行的步骤更多,则该算法没有真正有用的目的。更不用说以下简单的排序算法了O(infinity)

list = someList
while (list not sorted):
    doNothing

14
但是需要O(n)来检查它是否已排序,因此您可以获得O(n * n!)
erikkallen 2010年

3
@erikkallen:当然,我们可以提出一种算法来验证比O(n)差的排序。例如,对于数组中的每个元素,请验证其是否大于所有先前元素,就像插入排序一样。那是一个O(n ^ 2)算法,经过一点思考,我敢肯定我会提出更糟糕的建议。
David Thornley,2010年

7
@David Thornley:以下检查算法可能会显示出与bogosort相同的精神:选择两个随机元素,检查索引较小的元素小于或等于索引较大的元素,然后重复。保留正方形矩阵以查看已检查的组合。当然,检查此矩阵也可以随意走动...
Svante

19

Bogobogosort。是的,这是一回事。对于Bogobogosort,您是Bogosort的第一个元素。检查该元素是否已排序。作为一个要素,它将成为。然后添加第二个元素,然后对这两个元素进行Bogosort,直到将其排序为止。然后再添加一个元素,然后添加Bogosort。继续添加元素并进行Bogosorting,直到最终完成每个元素。这被设计成在宇宙热死之前永远无法成功获得任何可观的成就。


5
神圣的代码之母。我认为我们甚至可以简化Bogolplex。
MrKekson

19

您应该对Pessimal算法和单纯性分析的令人兴奋的领域进行一些研究。这些作者致力于开发具有最佳最佳情况的排序问题(您的bogosort的最佳情况是Omega(n),而slowsort(参见论文)具有非多项式的最佳情况时间复杂度)。


19

有一种叫做bogobogosort的类型。首先,它检查前两个元素,并对它们进行bogosorts。接下来,它检查前三个,对它们进行bogosorts,依此类推。

如果该列表在任何时候都处于混乱状态,它将通过bogosorting前2个重新开始。常规bogosort的平均复杂度为O(N!),此算法的平均复杂度为O(N!1!2!3!...N!)

编辑:为了让您知道这个数字有多大,对于20元素来说,该算法平均需要花费数3.930093*10^158 ,远远高于提议的宇宙热死亡数(如果发生)数10^100

假设年份为365.242天,而计算机每秒执行250,000,000个32位整数运算,则合并排序大约需要.0000004 几秒钟,气泡排序.0000016 几秒钟和bogosort需要数308 139 几天19 几小时35 几分钟22.306 几秒钟

Edit2:此算法的速度不如“算法”奇迹排序那样慢,它可能像这种排序一样,在成功对20个元素进行排序之前会使计算机陷入黑洞,但是如果这样做,我会估计平均复杂度的2^(32(the number of bits in a 32 bit integer)*N)(the number of elements)*(a number <=10^40)

由于重力加快了芯片移动的速度,并且存在2 ^ N个状态,即2^640*10^40大约5.783*10^216.762162762 几年,但是如果列表开始排序,则其复杂度仅O(N)比合并排序快,合并排序甚至仅为N log N在最坏的情况下。

EDIT3:这种算法实际上慢于奇迹的排序是大小变得非常大,说1000,因为我的算法将有一个运行时间2.83*10^1175546 ,而奇迹排序算法将有一个运行时间1.156*10^9657


1
很好的答案。遗憾的是它没有可见性
swyx

16

我和我的室友想出了两种

1)检查顺序2)也许发生了奇迹,请转到1

1)检查顺序是否正确; 2)将每个元素放入数据包中,然后将其从远程服务器上弹回自己。其中一些数据包将以不同的顺序返回,因此转到1


第二种几乎等同于bozo类。首先是聪明。
Mooing Duck 2012年

1
首先是奇迹排序。
查尔斯

14

总是有Bogobogosort(Bogoception!)。它对列表中越来越大的子集执行Bogosort,然后如果列表从未排序过,则重新开始。

for (int n=1; n<sizeof(list); ++n) {
  while (!isInOrder(list, 0, n)) {
    shuffle(list, 0, n);
  }
  if (!isInOrder(list, 0, n+1)) { n=0; }
}

5
我喜欢这种算法的设计意图是永远不会在“任何大小可观的列表因宇宙热死之前”完成
A.Grandt 2014年

10

1将要分类的物品放在索引卡上
2在大风天将它们扔到空中,距离您的房子一英里。
2将它们丢入篝火,并确认它们已被完全摧毁。
3检查您的厨房地板是否正确订购。
4如果顺序不正确,请重复。

最好的场景是O(∞)

根据KennyTM的敏锐观察,编辑以上内容。


9
不,这更糟,因为没有成功的机会。索引卡将如何进入您的厨房?他们在外面吹来。叫做,嗯,buttheadsort。
Patrick Karcher

我想他的意思扔卡在空中,然后检查你的楼里面,那里有保证是没有牌。尽管不是“命名”算法,但肯定更糟!
womp'4

10
@Patrick Quantum隧道。
kennytm 2010年

8
@KennyTM。那实际上发生在我身上。 任何物体消失或重新出现在宇宙中任何其他点的可能性极小,但不为零。 我猜这可能发生在上千张索引卡上。。。大井 丹吉特,我的算法有缺陷。我会解决的。。。
Patrick Karcher

3
有点像同时喝茶而不喝茶。或使用无限可能的驱动器进行太空旅行。
巴里·布朗

9

“您想成为什么样的人?” 分类

  1. 注意系统时间。
  2. 使用Quicksort(或其他任何合理的方法)进行排序,省略最后的交换。
  3. 注意系统时间。
  4. 计算所需的时间。要求扩展精度算术。
  5. 等待所需的时间。
  6. 执行最后一次交换。

它不仅可以实现任何可能的O(x)值(无穷大),而且时间证明是正确的(如果可以等待那么长的时间)。


8

没有什么比无穷更糟。


38
无限+ 1. Jinx,无回报。
zombat'4

24
不适用于1的极大值;)
zombat 2010年

8
无限概念的确使我大吃一惊,因为您可以拥有不同的“大小”的无限。例如,考虑所有整数的集合-它的大小是无限的。现在考虑所有偶数整数的集合-它的大小也是无限的,但显然也只有第一个集合的一半。两者都是无限的,但是大小不同。好棒。“大小”的概念根本无法在无限大的情况下起作用。
zombat'4

4
@zombat:您是在谈论基数,而不是无穷大,它是表示实线/复平面上趋势的符号。
kennytm 2010年

18
@zombat。偶数整数集的大小与整数集的大小相同,这表明您可以将它们一对一地对应在一起。现在,比整数更多的实数,如Cantor首先所示。
David Thornley,2010年

5

Bozo sort是一种相关算法,用于检查列表是否已排序,如果不排序,则随机交换两个项目。它具有最佳和最差情况下的性能,但直觉上我希望平均情况比Bogosort长。很难找到(或产生)有关该算法性能的任何数据。


5

π段

假设π包含所有可能的有限数组合。参见math.stackexchange问​​题

  1. 根据数组的大小确定所需的位数。
  2. 使用π位置的线段作为索引来确定如何对数组重新排序。如果段超出此数组的大小边界,请调整π小数偏移量并重新开始。
  3. 检查是否对重新排序的数组进行了排序。如果是低音,则调整偏移量并重新开始。

4

O(∞)在最坏情况下的性能甚至可能无法使其成为某些算法。

算法只是一系列步骤,您总是可以通过稍微调整一下算法来以比以前更多的步骤获得所需输出的方式来做更糟的事情。可以有目的地将有关步数的知识放到算法中,并使其终止,并且仅在X完成步数后才产生正确的输出。这X很可能约为O(n 2)或O(n n!)或算法想要执行的任何操作。这将有效地增加其最佳情况以及平均情况的范围。

但您最坏的情况不能超越:)


3

我最喜欢的慢速排序算法是stooge排序:

void stooges(long *begin, long *end) {
   if( (end-begin) <= 1 ) return;
   if( begin[0] < end[-1] ) swap(begin, end-1);
   if( (end-begin) > 1 ) {
      int one_third = (end-begin)/3;
      stooges(begin, end-one_third);
      stooges(begin+one_third, end);
      stooges(begin, end-one_third);
   }
}

最坏的情况是O(n^(log(3) / log(1.5))) = O(n^2.7095...)

另一个慢速排序算法实际上称为slowsort!

void slow(long *start, long *end) {
   if( (end-start) <= 1 ) return;
   long *middle = start + (end-start)/2;
   slow(start, middle);
   slow(middle, end);
   if( middle[-1] > end[-1] ) swap(middle-1, end-1);
   slow(start, end-1);
}

O(n ^ (log n))是最好的情况……甚至比stoogesort还要慢。


3
Recursive Bogosort (probably still O(n!){
if (list not sorted)
list1 = first half of list.
list 2 = second half of list.
Recursive bogosort (list1);
Recursive bogosort (list2);
list = list1 + list2
while(list not sorted)
    shuffle(list);
}

2

此页面是有关该主题的有趣阅读:http : //home.tiac.net/~cri_d/cri/2001/badsort.html

我个人最喜欢的是汤姆·达夫(Tom Duff)的傻傻排序:

/*
 * The time complexity of this thing is O(n^(a log n))
 * for some constant a. This is a multiply and surrender
 * algorithm: one that continues multiplying subproblems
 * as long as possible until their solution can no longer
 * be postponed.
 */
void sillysort(int a[], int i, int j){
        int t, m;
        for(;i!=j;--j){
                m=(i+j)/2;
                sillysort(a, i, m);
                sillysort(a, m+1, j);
                if(a[m]>a[j]){ t=a[m]; a[m]=a[j]; a[j]=t; }
        }
}


1

您可以通过随机运行“是否已排序”步骤来降低任何排序算法的速度。就像是:

  1. 创建与要排序的数组相同大小的布尔数组。将它们全部设置为false。
  2. 运行bogosort的迭代
  3. 选择两个随机元素。
  4. 如果两个元素相对于彼此排序(i <j && array [i] <array [j]),则将布尔数组上的两个索引都标记为true。过度,重新开始。
  5. 检查数组中的所有布尔值是否都为真。如果不是,请返回3。
  6. 做完了

1

是的,SimpleSort,在理论上它运行在O(-1)但这是相当于O(...9999)这又相当于O(∞ - 1),这正好也相当于O(∞)。这是我的示例实现:

/* element sizes are uneeded, they are assumed */
void
simplesort (const void* begin, const void* end)
{
  for (;;);
}

1

我刚才正在研究的一个问题涉及选择两个随机点,如果顺序错误,则反转它们之间的整个子范围。我在http://richardhartersworld.com/cri_d/cri/2001/badsort.html上找到了算法,该算法表示平均情况可能在O(n ^ 3)或O(n ^ 2 log n)左右(他不太确定)。

我认为有可能更有效地执行此操作,因为我认为有可能在O(1)时间内执行逆操作。

实际上,我只是意识到这样做将使我所说的全部成为可能,因为我刚刚意识到我所想到的数据结构将使访问O(log n)的随机元素并确定是否需要在O(n)求逆。 )。


1

随机子集排序。

给定n个元素的数组,请以1 / n的概率选择每个元素,将这些元素随机化,然后检查数组是否已排序。重复直到排序。

剩余的时间留给读者练习。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.