web-dev-qa-db-ja.com

O(N log N)複雑さ-線形に似ていますか?

だから、私はそのような些細な質問をするために埋葬されると思うが、私は何かについて少し混乱している。

JavaとCでクイックソートを実装し、いくつかの基本的な比較を行っていました。グラフは2本の直線として出てきました。Cは、100,000のランダムな整数を超えるJavaの対応物より4ms高速です。

Results

テスト用のコードはこちらにあります。

Android-benchmarks

(n log n)行がどのように見えるかはわかりませんでしたが、直線になるとは思いませんでした。これが期待される結果であり、コードでエラーを見つけようとしてはならないことを確認したかっただけです。

数式をExcelに貼り付けました。ベース10の場合、開始時にねじれのある直線のようです。これは、log(n)とlog(n + 1)の差が線形的に増加するためですか?

おかげで、

Gav

72
gav

グラフを大きくすると、O(n logn)が直線ではないことがわかります。しかし、はい、それは線形挙動にかなり近いです。理由を確認するには、いくつかの非常に大きな数の対数を取ります。

例(ベース10):

log(1000000) = 6
log(1000000000) = 9
…

したがって、1,000,000個の数字を並べ替えるには、O(n logn)並べ替えでわずかな係数6が追加されます(ほとんどの並べ替えアルゴリズムは2を底とする対数に依存するため、もう少し多くなります)。ひどいことではありません。

実際、この対数係数はsoが非常に小さいため、ほとんどの場合、確立されたO(n logn)アルゴリズムは線形時間アルゴリズムよりも優れています。顕著な例は、接尾辞配列データ構造の作成です。

簡単なケースが最近私をかみました 基数ソートを使用して短い文字列のクイックソートソートを改善しようとしたとき 。短い文字列の場合、この(線形時間)基数ソートはクイックソートよりも高速でしたが、基数ソートはソートする文字列の長さに大きく依存するため、比較的短い文字列には転換点がありました。

76
Konrad Rudolph

参考までに、クイックソートは実際にはO(n ^ 2)ですが、O(nlogn)の平均的なケースでは

参考までに、O(n)とO(nlogn)にはかなり大きな違いがあります。だからこそ、O(n) 。

グラフィカルなデモについては、以下を参照してください。

O(n) vs O(nlogn)

11
groundhog

同様の方法でさらに楽しくするために、標準の disjoint set data structuren操作にかかった時間をプロットしてみてください。漸近的に示されているnα(n)ここで、α (n)は Ackermann関数 の逆です(ただし、通常のアルゴリズムの教科書ではおそらくnlog lognまたは場合によってはn log *n)。入力サイズとして遭遇する可能性のあるあらゆる種類の数値について、α(n)≤5(そして実際にはlog *n≤5)、ただし、無限に漸近的に近づきます。

これから学べることは、漸近的な複雑さはアルゴリズムを考える上で非常に便利なツールですが、実際の効率とはまったく同じではないということです。

5
  1. 通常、O(n * log(n))アルゴリズムには2を底とする対数の実装があります。
  2. N = 1024、log(1024)= 10の場合、n * log(n)= 1024 * 10 = 10240の計算で、桁違いに増加します。

したがって、O(n * log(n))は、少量のデータについてのみ線形に似ています。

ヒント:クイックソートはランダムデータに対して非常にうまく機能し、O(n * log(n))アルゴリズムではないことを忘れないでください。

3

軸が正しく選択されていれば、任意のデータを線上にプロットできます:-)

ウィキペディアによると、Big-Oは最悪のケースです(つまり、f(x)はO(N)はf(x)がNによって「上に制限」されることを意味します) https://en.wikipedia.org/wiki/Big_O_notation

さまざまな一般的な機能の違いを示す素敵な一連のグラフを次に示します。 http://science.slc.edu/~jmarshall/courses/2002/spring/cs50/BigO/

Log(x)の導関数は1/xです。これは、xが増加するにつれてlog(x)がどれだけ速く増加するかです。直線ではありませんが、ゆっくりと曲がるので直線に見えるかもしれません。 O(log(n))を考えるとき、私はそれをO(N ^ 0 +)、つまりNの正の一定の累乗が最終的にそれを追い越すため、定数ではないNの最小の累乗と考えます。それは100%正確ではないので、そのように説明すると教授はあなたに腹を立てます。

2つの異なるベースのログの違いは、定数乗数です。 2つのベース間でログを変換するための式を検索します:(ここの「ベースの変更」の下: https://en.wikipedia.org/wiki/Logarithm )コツは、kとbを定数として扱うことです。

実際には、通常、プロットするデータに一時的な問題が発生します。あなたのプログラムの外のものに違いがあります(あなたのプログラムの前のCPUへのスワップ、キャッシュミスなど)。信頼できるデータを取得するには、多くの実行が必要です。定数は、Big O表記を実際のランタイムに適用しようとする最大の敵です。定数が大きいO(N)アルゴリズムは、十分に小さいNのO(N ^ 2)アルゴリズムよりも遅くなる可能性があります。

2
nobodyImportant

log(N)は(非常に)おおよそNの桁数です。そのため、ほとんどの場合、log(n)とlog(n + 1)にはほとんど違いがありません。

1
James Curran

その上に実際の直線をプロットしてみると、わずかな増加が見られます。 50,0000でのY値は、100,000での1/2 Y値よりも小さいことに注意してください。

そこにありますが、小さいです。だからこそO(nlog(n))がとても良い!

0
Chris Harris