The Art of Machinery

author
1 minute, 28 seconds Read

Any decent algorithms textbook will explain how fast sorting algorithms like quicksort and heapsort are, but it does not take crazy maths to prove that they are asymptotically fast as you can get possibly.

A pedantic note about notation

Most computer scientists use big-O notation to mean “asymptically equal, up to a constant scaling factor”, which is not quite what it means to other mathematicians.これは、ほとんどのコンピューター科学者が「一定のスケーリングファクターまで漸近的に等しい」という意味で big-O 表記を使用していますが、これは他の数学者にとって全く意味が異なることです。

比較ベースのソート

一度に2つの値を比較するアルゴリズム(quicksort や heapsort、その他の一般的なアルゴリズム)の特別な場合について見てみましょう。 1672>

A simple counting argument for the worst case

Aray of four elements, all different, in random order があるとする。 これを要素の1組だけを比較してソートできるでしょうか。 明らかに不可能ですが、不可能であることを証明する正当な理由が1つあります。定義上、配列を並べ替えるには、要素をどのように並べ替えて順番を決めるかが必要です。 言い換えれば、どの順列が必要かを知る必要があるのです。 可能な並べ換えはいくつあるのでしょうか? 最初の要素は4つの場所のいずれかに移動することができ、2番目の要素は残りの3つのうちの1つに行くことができ、3番目の要素には2つの選択肢があり、最後の要素は残りの1つの場所に行かなければならない。 つまり、4×3×2×1=4!=244通りの順列があるのですが、2つのものを比較した結果は2通りしかないのです。 「大きい “と “小さい “です。 もし可能な順列のリストを作ったら、”大きい “は順列8番、”小さい “は順列24番が必要だと判断できるかもしれませんが、残りの22個の順列がいつ必要かはわかりません。

2つの比較で、2×2=42 ㎤=4個の出力がありますが、それでも十分ではありません。 少なくとも5回の比較(25=322^5=32)を行わないと、シャッフルされた配列の可能性をすべてソートすることはできないのです。 W(N)W(N) をあるアルゴリズムで NN 個の要素をソートするのに必要な最悪の場合の比較回数とすると、

2W(N)≥N!2^{W(N)} と言うことができるのです。 \N!}

対数の底2をとると

W(N)≥log2N!W(N) \log_2{N!}

Asymptically, N!N! はNNN^Nのように成長するので

W(N)⪰logNN=NlogNW(N) \log{N^N} = Nlog{N}

そしてこれは出力を数えるだけで最悪の場合O(NlogN)O(Nlog N) limitとなるんだ。

Average case from information theory

このカウントの議論を少し情報理論で拡張すると、より強い結果を得ることができる。 ここでは、ソートアルゴリズムを情報伝達のためのコードとして使用する方法を説明します。

  1. 私はある数字、例えば15を考える
  2. 私は4つの要素の並べ替えリストから並べ替え#15を探す
  3. 私はこの並べ替えに対してソートアルゴリズムを実行し「大きい」「小さい」の比較結果をすべて記録する
  4. 私は比較結果をバイナリコードであなたに伝える
  5. あなたは私のソートアルゴリズムの実行を再演奏してください。 ステップバイステップで、必要に応じて比較結果のリストを参照する
  6. 私がどのように配列を並べ替えたかがわかったので、並べ替えを逆にして元の配列を見つけることができます
  7. 並べ替えリストで元の配列を調べると、私が15

という数字を送信したことがわかりました。 つまり、ソートアルゴリズムは通常の符号化方式と同じ法則に縛られているのです。普遍的なデータ圧縮器は存在しないことを証明する定理もその一つです。 私はアルゴリズムが行う比較ごとに1ビットを送信したので、情報理論によれば、平均して、比較の回数は私のデータを表現するのに必要なビット数以上でなければならないのです。 より専門的には、平均比較回数は、ビット数で測定した入力データのシャノンエントロピー以上でなければならない。 エントロピーは、何かの情報量、または予測不可能性の数学的尺度である。

偏りなく任意の順序になりうる NN 個の要素の配列がある場合、エントロピーは最大になり log2N!} ビットになる。 これは、O(NlogN)O(Nlog{N})が任意の入力での比較ベースのソートの最適平均であることを証明している。

以上が理論だが、実際のソートアルゴリズムはどう比較しているか。 以下は、配列をソートするために必要な比較の平均数のプロットです。 ナイーブなクイックソートとフォード・ジョンソンのマージ挿入ソートに対して理論的最適値を比較しました。これは比較を最小限にするように設計されています(ただし、比較を最小限にするよりも重要なことがあるため、全体としてクイックソートより速いことはほとんどありません)。 1959 年に開発されて以来、マージ挿入ソートはさらにいくつかの比較を絞り込むために調整されてきましたが、このプロットはすでにほぼ最適であることを示しています。 最下段が理論的な最適値。 約1%以内はマージ挿入ソート。 Naïve quicksort は最適値の約 25% 以内です。

少しの理論がこのように緊密な実用的結果を与えるのは素晴らしいことです。

これまでのまとめ

これまで証明されたことは以下の通りです。

  1. 配列が任意の順序で開始できる場合、最悪のケースで少なくとも O(NlogN)O(Nlog{N}) 比較が必要
  2. 比較の平均回数は少なくとも配列のエントロピーでなければならない。 これはランダムな入力ではO(NlogN)O(Nlog{N})である

入力が低エントロピー(言い換えれば、より予測可能)であれば#2により比較ベースのソートアルゴリズムはO(NlogN)O(Nlog{N})より速くなることに注意すること。 Merge sortは、入力が多くのソートされた部分配列を含む場合、O(N)O(N)に近い速度になります。 挿入ソートは、入力が少し乱される前にソートされた配列であれば O(N)O(N) に近い値です。

General sorting algorithms

比較ベースのソートは実際には興味深い特殊ケースですが、コンピュータの他の命令と比較してCMPは理論的に何も特別ではありません。

  1. Most computer instructions have more than two possible outputs, but still have a limited number
  2. The limited number of outputs means that one instruction can only process a limited amount of entropy

that gives us the same O(NlogN)O(Nlog{N}) lower bound on the number of instructions.The only limited number of outputs.This can be generalised to any sort algorithm to a long distance. 物理的に実現可能なコンピュータは、一度に限られた数の命令しか処理できないので、必要な時間についてもO(NlogN)O(Nlog{N})の下界となります。

But what about “faster” algorithms?

The general O(NlogN)O(Nlog {N}) boundの最も役立つ実用上の意味合いは、任意の漸近高速アルゴリズムについて聞いた場合、それが何らかの「不正」でなければならないと分かるということです。 それは、任意の大きさの配列にスケールする汎用ソートアルゴリズムではないことを意味する、いくつかのキャッチがあるに違いない。 それはまだ有用なアルゴリズムかもしれませんが、細かい印刷物をよく読むことをお勧めします。

よく知られている例は基数ソートです。 これはよく O(N)O(N) ソートアルゴリズムと呼ばれるが、すべての数値が kk ビットに収まる場合にのみ機能し、実際には O(kN)O(kN) であることが問題なのである。 8ビットの機械があるとする。 8ビットで28=2562^8=256通りの数を表現できますから、何千個もの数の配列があれば、重複が発生することになります。 この場合、216=65,5362^16=65,536個の数字を区別して表現することができるようになります。 32ビットでは、232=4,294,967,2962^32 = 4,294,967,296の数を表現することができます。 配列のサイズが大きくなると、必要なビット数も大きくなる傾向があります。 NN個の異なる数字を区別して表現するには、k≥log2Nk \log_2{N} が必要になります。 つまり、配列に重複が多くても構わないのであれば、O(kN)O(kN)は実質O(NlogN)O(Nlog{N})です。

一般のケースで入力データがO(NlogN)O(Nlog{N})で必要というのは、実はそれだけで全体の結果を証明することになるのです。 32ビットマシンで何十億もの整数をソートする必要はほとんどないし、64ビットマシンの限界に達した人がいたとしても、他の人には教えていないからだ

Similar Posts

コメントを残す

メールアドレスが公開されることはありません。