私の同僚は、今朝、ソートアルゴリズムの議論で私を大学時代に戻しました。 StupidSort のようなお気に入りについて思い出したところ、私たちの1人はO(n!)
であるソートアルゴリズムを見たことがあると確信していました。それにより、私が見つけた「最悪の」ソートアルゴリズムを探し始めました。
完全にランダムな並べ替えはかなり悪い(つまり、要素をランダム化する-それは順番通りですか?いいえ?再びランダム化する)と仮定し、見回して、明らかに BogoSortと呼ばれることを発見しました。またはMonkey Sort、または単にランダムソート 。
Monkey Sortは、O(∞)
の最悪ケースのパフォーマンス、O(n)
のベストケースのパフォーマンス、およびO(n·n!)
の平均パフォーマンスを持っているようです。
O(n·n!)
よりも平均パフォーマンスが悪い名前付きアルゴリズムはありますか?または、一般的にMonkey Sortよりも愚かですか?
David Morgan-Mar の難解なアルゴリズムページから:Intelligent Design Sort
はじめに
インテリジェントデザインソートは、インテリジェントデザインの理論に基づいたソートアルゴリズムです。
アルゴリズムの説明
元の入力リストが正確な順序で並んでいる確率は、1 /(n!)です。この可能性は非常に低いので、偶然にこれが起こったと言うのは明らかに馬鹿げているので、インテリジェントなソーターによってその順序に意識的に入れられたに違いありません。したがって、「昇順」についての私たちの素朴な人間の理解を超越する何らかの方法で既に最適にソートされていると想定するのは安全です。私たち自身の先入観に準拠するようにその順序を変更しようとすると、実際にはソートが少なくなります。
分析
このアルゴリズムは時間的に一定であり、リストをその場でソートし、追加のメモリをまったく必要としません。実際、疑わしい技術的なコンピューターは必要ありません。ソーターを称賛してください!
フィードバック
ゲイリー・ロジャースはこう書いている:
ソートを時間的に一定にすることは、ソーターの力を否定します。ソーターは時間外に存在するため、ソートは時間をかけません。ソートの検証に時間がかかると、ソーターの役割が損なわれます。したがって、この特定のソートには欠陥があり、「ソーター」に起因するものではありません。
異端!
何年も前、私は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は、このステップで使用する明らかなアルゴリズムです。
編集:厳密に言えば、これはアルゴリズムではありません。終了が保証されていないためです。 「アルゴリズムではない」は「より悪いアルゴリズム」とみなされますか?
量子力学の多世界解釈が正しいと仮定する分類アルゴリズム:
アルゴリズムの終わりに、リストは残っている唯一のユニバースでソートされます。このアルゴリズムは、最悪の場合O(N)および平均の場合O(1)時間かかります。実際、実行される比較の平均数は2です。2番目の要素で宇宙が破壊される可能性は50%、3番目の要素で宇宙が破壊される可能性は25%です。
誰もまだ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
パフォーマンスの点ではひどいです(特に2番目の例)。 2つの数字を並べ替えるのに3.5か月近く待つのはちょっと悪い。
here のように、ジングルソート。
リストの各値をクリスマスに別の子供に渡します。ひどい人間である子どもたちは、贈り物の価値を比較し、それに応じて自分自身を分類します。
ランダム配列の生成を提案し、ソートされているかどうかを確認してから、データがソートされる配列と同じかどうかを確認することを提案した講師がいました。
ベストケースO(N)(初めての赤ちゃん!)最悪のケースO(なし)
アルゴリズムに何らかの意味がある場合、O(n!)
は達成可能な最悪の上限です。
ソートされるセットの順列の各可能性をチェックするのにn!
ステップがかかるため、それ以上悪化することはありません。
それよりも多くのステップを実行している場合、アルゴリズムには実用的な目的はありません。 O(infinity)
を使用した次の単純なソートアルゴリズムは言うまでもありません:
list = someList
while (list not sorted):
doNothing
Pessimal Algorithms and Simplexity Analysis のエキサイティングな分野について調査する必要があります。これらの著者は、ペシマルベストケース(bogosortのベストケースはOmega(n)であり、slowsort(論文を参照)は非多項式ベストケースの時間の複雑さを伴う)でソートを開発する問題に取り組んでいます。
ボゴボゴソート。はい、それは事です。 Bogobogosortでは、最初の要素をBogosortにします。その1つの要素がソートされているかどうかを確認します。 1つの要素であるため、そうなります。次に、2番目の要素を追加し、ソートされるまでこれら2つをBogosortします。次に、もう1つの要素を追加してから、Bogosortを追加します。すべての要素が最終的に完了するまで、要素とBogosortingの追加を続けます。これは、宇宙の熱死の前に、かなりのリストで成功しないように設計されました。
大学でルームメートを思いついた2種類があります
1)注文を確認する2)奇跡が起こったので、1に進む
そして
1)順序が正しいかどうかを確認し、そうでない場合は2)各要素をパケットに入れて、離れたサーバーから自分に返送します。これらのパケットの一部は異なる順序で返されるため、1に進みます
Bogobogosortと呼ばれる種類があります。最初に、最初の2つの要素をチェックし、それらをbogosortします。次に、最初の3つをチェックし、それらをbogosortsします。リストがいつでも順序が狂っている場合、最初の2つを再度bogosortingすることにより再起動します。通常のbogosortの平均複雑度はO(N!)であり、このアルゴリズムの平均複雑度はO(N!1!2!3!... N!)です。編集:この数がどれだけ大きいかを知るために、 20個の要素の場合、このアルゴリズムの平均所要時間は平均3.930093 * 10 ^ 158年で、提案された宇宙の熱死(発生した場合)10 ^ 100年を大きく上回りますが、マージソートには約.0000004秒、バブルソート.0000016がかかります秒、およびbogosortは308年、139日、19時間、35分、22.306秒かかります。1年が365.242日で、コンピューターが1秒あたり250,000,000 32ビット整数演算を行うと仮定します。編集2:このアルゴリズムは「アルゴリズム」の奇跡のソートほど遅くはありません。おそらくこのソートのように、20個の要素を正常にソートする前にコンピュータをブラックホールに吸い込ませますが、そうすると平均的な複雑さを推定しますof 2 ^(32(32ビット整数のビット数)N)(要素数)(重力<= 10 ^ 40年、重力によりチップのアルファ移動が加速されるため、 2 ^ N個の状態があり、これは2 ^ 640 * 10 ^ 40、または約5.783 * 10 ^ 216.762162762年ですが、リストが並べ替えられた場合、その複雑さはO(N)になり、マージ並べ替えよりも速くなります。 Edit3:このアルゴリズムの実行時間は2.83 * 10 ^ 1175546年なので、サイズが非常に大きくなると、たとえば1000になると、このアルゴリズムは実際には奇跡のソートよりも遅くなります。奇跡ソートアルゴリズムの実行時間は1.156 * 10 ^ 9657年です。
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; }
}
1インデックスカードに並べ替えるアイテムを置く2風の強い日、家から1マイル離れた場所にそれらを投げ捨てます。
2それらをき火に投げ、完全に破壊されたことを確認します。
3キッチンの床が正しい順序かどうかを確認します。
4正しい順序でない場合は繰り返します。
ベストケースscenerioはO(∞)
編集上記はKennyTMによる鋭い観察に基づいています。
無限に近い考えられるO(x)の値を実装できるだけでなく、所要時間が正しいことを証明できます(長い間待つことができる場合)。
無限より悪いものはありません。
πのセグメント
Πにはすべての可能な有限数の組み合わせが含まれていると仮定します。 math.stackexchange question を参照してください
Bozoソートは、リストがソートされているかどうかをチェックし、ソートされていない場合は2つのアイテムをランダムに交換する関連アルゴリズムです。最良の場合と最悪の場合のパフォーマンスは同じですが、直感的には平均的なケースのほうがBogosortよりも長いと思います。このアルゴリズムのパフォーマンスに関するデータを見つける(または生成する)のは困難です。
O(∞)の最悪の場合のパフォーマンスは、 some に従ったアルゴリズムにならないかもしれません。
アルゴリズムは単なる一連の手順であり、以前よりも多くの手順で目的の出力を得るために少し調整することで、常に悪化させることができます。アルゴリズムに取られたステップ数の知識を意図的に入れて、X
のステップ数が行われた後にのみアルゴリズムを終了し、正しい出力を生成することができます。 X
は、O(n2)またはO(nn!)またはアルゴリズムが実行したいことは何でも。これにより、平均的なケース境界だけでなく、そのベストケースも効果的に増加します。
しかし、最悪のシナリオを突破することはできません:)
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);
}
私のお気に入りの低速ソートアルゴリズムは、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よりもさらに遅くなります。
このページは、このトピックに関する興味深い記事です。 http://home.tiac.net/~cri_d/cri/2001/badsort.html
私の個人的なお気に入りは、トム・ダフの愚かな振る舞いです:
/*
* 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; }
}
}
ダブルボゴソート
Bogosortを2回実行し、結果を比較する(ソートされていることを確認するため)
私がちょうど取り組んでいたことの1つは、2つのランダムポイントを選択することであり、それらの順序が間違っている場合は、それらの間の部分範囲全体を逆にします。 http://richardhartersworld.com/cri_d/cri/2001/badsort.html でアルゴリズムを見つけました。平均的なケースはおそらくO(n ^ 3)またはO( n ^ 2 log n)(彼はよくわからない)。
O(1)の時間で反転操作を実行できる可能性があるため、より効率的に実行できる可能性があると思います。
実際、私は、考えていたデータ構造がO(log n)のランダム要素にアクセスし、O(n )。
「ソートされていますか」ステップをランダムに実行することにより、ソートアルゴリズムを遅くすることができます。何かのようなもの:
ランダムサブセットソート。
N個の要素の配列が与えられたら、確率1/nで各要素を選択し、これらの要素をランダム化し、配列がソートされているかどうかを確認します。ソートされるまで繰り返します。
予想時間は、読者の演習として残されています。
はい、SimpleSort、理論的にはO(-1)
で実行されますが、これは O(...9999)
と同等 であり、これはO(∞-1)と同等です。 O(∞)と同等です。これが私の実装例です。
/* element sizes are uneeded, they are assumed */
void
simplesort (const void* begin, const void* end)
{
for (;;);
}