web-dev-qa-db-ja.com

アルゴリズムにO(log log n)の複雑さをもたらす原因は何ですか?

この以前の質問 は、アルゴリズムにO(log n)の複雑さをもたらす可能性があるいくつかの要因に対処します。

アルゴリズムに時間の複雑さO(log log n)を持たせる原因は何ですか?

93
templatetypedef

O(log log n)の用語はさまざまな場所に表示されますが、通常、このランタイムに到達する2つの主要なルートがあります。

平方根による縮小

リンクされた質問への答えで述べたように、アルゴリズムが時間の複雑さO(log n)を持つ一般的な方法は、各反復で一定の係数で入力のサイズを繰り返し削減することでアルゴリズムが機能することです。この場合、アルゴリズムはO(log n)の反復後に終了する必要があります。これは、O(log n)を定数で除算した後、アルゴリズムが問題サイズを0または1に縮小する必要があるためです。 、バイナリ検索の複雑さはO(log n)です。

興味深いことに、O(log log n)の形式のランタイムを生成する問題のサイズを縮小する同様の方法があります。各レイヤーで入力を半分に分割する代わりに、各レイヤーでサイズの平方根を取るとどうなりますか?

たとえば、数字65,536を使用してみましょう。 1になるまで、これを2で割る必要がありますか?これを行うと、

  • 65,536/2 = 32,768
  • 32,768/2 = 16,384
  • 16,384/2 = 8,192
  • 8,192/2 = 4,096
  • 4,096/2 = 2,048
  • 2,048/2 = 1,024
  • 1,024/2 = 512
  • 512/2 = 256
  • 256/2 = 128
  • 128/2 = 64
  • 64/2 = 32
  • 32/2 = 16
  • 16/2 = 8
  • 8/2 = 4
  • 4/2 = 2
  • 2/2 = 1

このプロセスには16ステップが必要で、65,536 = 2の場合もあります16

しかし、各レベルで平方根を取ると、

  • √65,536= 256
  • √256= 16
  • √16= 4
  • √4= 2

2に達するのに4ステップしか必要ないことに注意してください。これはなぜですか?さて、このシーケンスを2のべき乗の観点から書き換えましょう。

  • √65,536=√216 =(2161/2 = 28 = 256
  • √256=√28 =(281/2 = 24 = 16
  • √16=√24 =(241/2 = 22 = 4
  • √4=√22 =(221/2 = 21 = 2

シーケンス2に従っていることに注意してください。16 →28 →24 →22 →21。各反復で、2のべき乗の指数を半分にカットします。興味深いのは、これは既にわかっていることと結びついているためです-数値kは、ゼロになる前にO(log k)回だけ半分に分割できます。

したがって、任意の数nを取得し、n = 2として記述しますk。 nの平方根を取るたびに、この方程式の指数が半分になります。したがって、kが1以下に低下する前に適用されるO(log k)平方根のみが存在する可能性があります(この場合、nは2以下に低下します)。 n = 2からk、これはk = log2 n、したがって取得される平方根の数はO(log k)= O(log log n)です。したがって、元の問題サイズの平方根であるサイズの部分問題に問題を繰り返し減らすことによって機能するアルゴリズムがある場合、そのアルゴリズムはO(log log n)ステップの後に終了します。

この実例の1つは、 van Emde Boas tree (vEB-tree)データ構造です。 vEBツリーは、0〜N-1の範囲の整数を格納するための特殊なデータ構造です。次のように機能します。ツリーのルートノードには√Nのポインターがあり、0〜N-の範囲を分割します√N個の整数の範囲をそれぞれ保持する√N個のバケットに1つ。次に、これらのバケットはそれぞれ内部的に√(√N)バケットに分割され、各バケットにはおよそ√(√N)個の要素が保持されます。ツリーをトラバースするには、ルートから始めて、どのバケットに属しているかを判別し、適切なサブツリーで再帰的に続行します。 vEB-treeの構造により、O(1)時間でどのサブツリーが下降するかを決定できます。したがって、O(log log N)ステップの後、ツリーの最下部に到達します。 。したがって、vEBツリーでの検索にかかる時間はO(log log N)のみです。

別の例は Hopcroft-Fortuneの最も近いポイントペアアルゴリズム です。このアルゴリズムは、2Dポイントのコレクションから2つの最も近いポイントを見つけようとします。バケットのグリッドを作成し、それらのバケットにポイントを配布することで機能します。アルゴリズムのいずれかのポイントで、√Nポイントを超えるバケットが見つかった場合、アルゴリズムはそのバケットを再帰的に処理します。したがって、再帰の最大の深さはO(log log n)であり、再帰ツリーの分析を使用すると、ツリーの各レイヤーがO(n)動作することがわかります。したがって、アルゴリズムの合計ランタイムはO(n log log n)です。

小さい入力でのO(log n)アルゴリズム

サイズO(log n)のオブジェクトのバイナリ検索などのアルゴリズムを使用してO(log log n)ランタイムを実現する他のアルゴリズムがいくつかあります。たとえば、 x-fast trie データ構造は、高さO(log U)のツリーのレイヤーでバイナリ検索を実行するため、一部の操作のランタイムはO(log log U)です。 。関連する y-fast trie は、それぞれO(log U)ノードのバランスの取れたBSTを維持することにより、O(log log U)ランタイムの一部を取得し、それらのツリーでの検索を時間内に実行できるようにしますO(log log U)。 tango tree および関連する multisplay tree データ構造は、それぞれO(log n)アイテムを含むツリーを維持するため、分析ではO(log log n)の用語で終わります。

その他の例

他のアルゴリズムは、他の方法でランタイムO(log log n)を実現します。 補間検索 は、実行時O(log log n)でソートされた配列内の数値を見つけることを期待していますが、分析はかなり複雑です。最終的に、分析は、反復回数が数nに等しく、nが2-k ≤2。この場合、log log nが正しい解です。 Cheriton-Tarjan MSTアルゴリズム のようないくつかのアルゴリズムは、複雑な制約付き最適化問題を解くことにより、O(log log n)を含むランタイムに到達します。

お役に立てれば!

192
templatetypedef

時間の複雑さでO(log log n)の要因を見る1つの方法は、他の答えで説明したもののような除算によるものですが、この要因を見る別の方法があります。そして、アルゴリズムの近似/時間と硬度/ ...であり、アルゴリズムに人為的な反復があります。

たとえば、SSSP(Single source shortest path)には平面グラフ上にO(n)アルゴリズムがありますが、その複雑なアルゴリズムの前には、実行時間O(n log log n)、アルゴリズムのベースは次のとおりです(非常に大まかな説明です。この部分の理解をスキップし、答えの他の部分を読むことを提案します)。

  1. グラフをサイズO(log n /(log log n))の部分に分割しますが、いくつかの制限があります。
  2. 上記の各部分が新しいグラフG 'のノードであると仮定すると、時間O(| G' | * log | G '|)でG'のSSSPを計算します。 = O(| G | * log log n/log n)で、(log log n)ファクターを確認できます。
  3. 各部分のSSSPを計算します。O(| G '|)部分があり、すべての部分のSSSPを時間内に計算できるためです| n/logn | * | log n/log logn * log(logn/log log n)。
  4. 重みを更新すると、この部分はO(n)で実行できます。詳細については、 この講義ノート が適切です。

しかし、私のポイントは、ここでサイズO(log n /(log log n))になるように分割を選択することです。 O(log n /(log log n)^ 2)のような他の部門を選択すると、より高速に実行され、別の結果が得られます。つまり、多くの場合(近似アルゴリズムやランダム化アルゴリズム、または上記のSSSPのようなアルゴリズム)、何か(サブ問題、可能なソリューションなど)を反復処理するとき、そのトレードに対応する反復回数を選択します(時間/空間/アルゴリズムの複雑さ/アルゴリズムの定数因子、...)があります。実際の動作アルゴリズムでは、「log log n」よりも複雑なものが見られるかもしれません。

3
Saeed Amiri