web-dev-qa-db-ja.com

なぜmergesort O(log n)なのですか?

Mergesortは、分割統治アルゴリズムであり、入力が繰り返し半分になるため、O(log n)です。しかし、それはO(n)ではありませんか?入力が各ループで半分になっている場合でも、各半分の配列でスワッピングを実行するには、各入力項目を反復する必要がありますか?これは本質的に漸近的ですO(n)私の心の中で。可能であれば、例を挙げて、操作を正しくカウントする方法を説明してください!私はまだ何もコーディングしていませんが、オンラインでアルゴリズムを調べています。私はまた、マージソートの動作を視覚的に示すためにウィキペディアが使用しているもののgifも添付しました。

enter image description here

30
perseverance

O(log(n))ではなく、O(n * log(n))です。正確に推測したように、入力全体を反復処理する必要があり、これはO(log(n))回発生する必要があります(入力は半分にできるO(log(n))回)。log(n)回繰り返されたn個のアイテムはO(n log(n))を与えます。

比較ソートはこれより速く動作できないことが証明されています。基数ソートなどの入力の特別なプロパティに依存するソートのみが、この複雑さを克服できます。マージソートの一定の要素は通常それほど大きくありませんが、複雑性が低いアルゴリズムほど時間がかかりません。

63
DeadMG

マージソートの複雑さはO(nlogn)であり、O(logn)ではありません。

マージソートは、分割統治アルゴリズムです。 3つのステップで考えてみてください。

  1. 除算ステップは、各サブ配列の中点を計算します。この各ステップは、O(1)時間かかります。
  2. Conquerステップは、n/2(偶数nの場合)要素の2つのサブ配列をそれぞれ再帰的にソートします。
  3. マージステップは、O(n)時間かかるn個の要素をマージします。

ここで、ステップ1と3の場合、つまりO(1)とO(n)の間では、O(n)の方が高いです。ステップ1と3を考えてみましょう。合計O(n)時間の合計。ある定数cではcnだとしましょう。

これらのステップは何回実行されますか?

これについては、下のツリーを見てください。上から下までの各レベルについて、レベル2は、長さがそれぞれn/2の2つのサブ配列に対してmergeメソッドを呼び出します。ここでの複雑さは2 *(cn/2)= cnレベル3は、長さがそれぞれn/4の4つのサブ配列に対してマージメソッドを呼び出します。ここでの複雑さは4 *(cn/4)= cnなどです...

現在、この木の高さは、指定されたnに対して(logn + 1)です。したがって、全体的な複雑度は(logn + 1)*(cn)です。つまり、O(nlogn)はマージソートアルゴリズムの場合です。

Merge sort for n elements

画像クレジット: Khan Academy

38
Shantanu Alshi

マージソートは再帰的なアルゴリズムであり、時間の複雑さは次の再帰関係として表すことができます。

T(n) = 2T(n/2) + ɵ(n)

上記の繰り返しは、Recurrence TreeメソッドまたはMasterメソッドを使用して解決できます。これはマスターメソッドのケースIIに該当し、再発の解はɵ(n log n)です。

マージソートは常に3つのケース(最悪、平均、最良)でɵ(nLogn)です。これは、マージソートが常に配列を2つに分割し、2つの半分をマージするのに線形時間を要するためです。

入力配列を2つの半分に分割し、2つの半分に対して自身を呼び出してから、ソートされた2つの半分をマージします。 merg()関数は、2つの半分をマージするために使用されます。 merge(arr、l、m、r)は、arr [l..m]とarr [m + 1..r]がソートされていると想定し、ソートされた2つのサブ配列を1つにマージする重要なプロセスです。詳細については、次のC実装を参照してください。

MergeSort(arr[], l,  r)
If r > l
     1. Find the middle point to divide the array into two halves:  
             middle m = (l+r)/2
     2. Call mergeSort for first half:   
             Call mergeSort(arr, l, m)
     3. Call mergeSort for second half:
             Call mergeSort(arr, m+1, r)
     4. Merge the two halves sorted in step 2 and 3:
             Call merge(arr, l, m, r)

enter image description here

図を詳しく見ると、サイズが1になるまで配列が2つの半分に再帰的に分割されていることがわかります。サイズが1になると、マージプロセスが実行され、完全な配列になるまで配列のマージが開始されます。合併。

9
Nishant sethi

比較ベースのソートアルゴリズムには下限????(n*log(n))があります。つまり、比較ベースのソートアルゴリズムでO(log(n))時間の複雑さを持つことはできません。

ちなみに、マージソートはO(n*log(n))です。このように考えてください。

_[ a1,a2,         a3,a4,         a5,a6,          a7,a8     .... an-3,an-2,     an-1, an ] 
   \ /            \  /           \ /             \  /            \  /            \  /    
    a1'            a3'            a5'             a7'            an-3'           an-1'    
      \            /                \             /                 \             /
            a1''                          a5''                       an-3''
             \                             /                         /
                          a1'''                                     /
                           \
                                              a1''''
_

これは逆二分木に見えます。

入力サイズをnとします。

各_a_n_は要素のリストを表します。最初の行の_a_n_には要素が1つしかありません。

各レベルで、平均のマージコストの合計はnです(コストが低いコーナーケースが存在します[1])。そして、木の高さはlog_2(n)です。

したがって、マージソートの時間の複雑さはO(n*log_2(n))です。

[1]すでにソートされているリストでソートする場合、これはベストケースと呼ばれます。コストはn/2 + n/4 + n/8 + .... + 1 = 2^log_2(n) -1 ~ O(n)に削減されました。 (長さnが2の累乗であると想定)

0
W. PC