ヒープの構築はどのようにしてO(n)時間の複雑さになりますか?


494

誰かがどのようにしてヒープを構築することがO(n)複雑になるかを説明するのを手伝ってくれる?

アイテムをヒープに挿入することはO(log n)であり、挿入はn / 2回繰り返されます(残りはリーフであり、ヒーププロパティに違反することはできません)。つまり、これは複雑さがであることを意味しO(n log n)ます。

つまり、「ヒープ化」する各アイテムについて、これまでのヒープの各レベル(log nレベル)に対して1回フィルターをかける必要がある可能性があります。

何が欠けていますか?


ヒープを「構築する」とはどういう意味ですか?
mfrankli 2012年

ヒープソートの場合と同様に、ソートされていない配列を取得し、ヒープのルールに準拠するまで、上半分の各要素を
フィルターダウン

2
私が見つけた唯一のことはこのリンクでした:Buildheapの複雑さはΘ(n lg n)–呼び出しあたりΘ(lg n)のコストでHeapifyへのn回の呼び出しですが、この結果はΘ(n)に改善できます cs.txstate.edu/~ch04/webtest/teaching/courses/5329/lectures/...
GBA

2
@Gba MITからのこのビデオを見る:彼はO(n)を取得する方法について少し説明していますyoutube.com/watch?v=B7hVxCmfPtM
CodeShadow

2
@CodeShadowの説明への直接リンク:youtu.be/B7hVxCmfPtM
sha1

回答:


435

このトピックにはいくつかの疑問が潜んでいると思います。

  • O(n)時間buildHeapで実行できるようにどのように実装しますか?
  • 正しく実装されている場合buildHeapO(n)時間で実行されることをどのように示しますか?
  • ヒープソートをO(n log n)ではなくO(n)時間で実行するために同じロジックが機能しないのはなぜですか?

O(n)時間buildHeapで実行できるようにどのように実装しますか?

多くの場合、これらの質問に対する答えは違いに焦点を当てるsiftUpsiftDown。間に正しい選択をするsiftUpsiftDown取得することが重要であるO(N)のパフォーマンスをbuildHeap、しかし、1つの違いを理解する助けに何もしませんbuildHeapし、heapSort一般的に。実際、両方の適切な実装buildHeapheapSortなりますのみ使用しますsiftDown。このsiftUp操作は、既存のヒープへの挿入を実行するためにのみ必要であるため、たとえば、バイナリヒープを使用して優先度キューを実装するために使用されます。

最大ヒープがどのように機能するかを説明するためにこれを書きました。これは、ヒープのソートまたは優先度キューに通常使用されるヒープのタイプであり、値が高いほど優先度が高いことを示します。最小ヒープも役立ちます。たとえば、昇順の整数キーまたはアルファベット順の文字列を持つアイテムを取得する場合などです。原則はまったく同じです。ソート順を切り替えるだけです。

ヒーププロパティバイナリヒープ内の各ノードは、少なくともその子の両方として大きいようでなければならないことを指定します。特に、これはヒープ内の最大のアイテムがルートにあることを意味します。ふるいにかけることとふるいにかけることは、本質的に反対の方向に同じ操作です。問題のあるノードを、ヒーププロパティを満たすまで移動します。

  • siftDown 小さすぎるノードをその最大の子と入れ替えます(その結果、ノードが下に移動します)。少なくとも、その下の両方のノードと同じ大きさになります。
  • siftUp 大きすぎるノードをその親ノードと入れ替えます(それにより、そのノードを上に移動します)。

操作の数のために必要siftDownsiftUpノードが移動する必要がある可能性があり、距離に比例しています。の場合siftDown、これはツリーの最下部までの距離であるため、ツリーsiftDownの最上位にあるノードではコストが高くなります。を使用するsiftUpと、作業はツリーの最上部までの距離に比例するため、ツリーsiftUpの最下部にあるノードではコストが高くなります。最悪の場合、両方の操作はO(log n)ですが、ヒープでは、1つのノードのみが一番上にあり、半分のノードが一番下のレイヤーにあります。したがって、すべてのノードに操作を適用する必要がある場合は、を優先siftDownすることはそれほど驚くべきことではありませんsiftUp

このbuildHeap関数は、並べ替えられていない項目の配列を受け取り、それらがすべてヒーププロパティを満たすまでそれらを移動して、有効なヒープを生成します。ここで説明buildHeapしたsiftUpとのsiftDown操作を使用するには、2つの方法があります。

  1. ヒープの最上部(配列の先頭)から開始し、siftUp各項目を呼び出します。各ステップで、以前にふるいにかけられたアイテム(配列内の現在のアイテムの前のアイテム)が有効なヒープを形成し、次のアイテムをふるいにかけることで、ヒープ内の有効な位置に配置します。各ノードをふるいにかけた後、すべてのアイテムがヒーププロパティを満たします。

  2. または、反対方向に進みます。アレイの最後から開始して、前方に向かって後方に移動します。各反復で、アイテムが正しい位置に来るまで下にふるいにかけます。

どちらの実装buildHeapがより効率的ですか?

これらのソリューションはどちらも有効なヒープを生成します。当然のことながら、より効率的なのは、を使用する2番目の操作ですsiftDown

ましょH =ログNヒープの高さを表しています。siftDownアプローチに必要な作業は合計で与えられます

(0 * n/2) + (1 * n/4) + (2 * n/8) + ... + (h * 1).

合計の各項には、指定された高さのノードが移動しなければならない最大距離(最下層の場合はゼロ、ルートの場合はh)にその高さのノード数を掛けた値があります。対照的に、siftUp各ノードの呼び出しの合計は

(h * n/2) + ((h-1) * n/4) + ((h-2)*n/8) + ... + (0 * 1).

2番目の合計が大きいことは明らかです。最初の項だけではhn / 2 = 1/2 n log nなので、このアプローチはせいぜいO(n log n)の複雑さです。

siftDownアプローチの合計が確かにO(n)であることをどのように証明しますか?

1つの方法(これも機能する他の分析があります)は、有限和を無限級数に変換してから、テイラー級数を使用することです。ゼロである最初の項は無視できます。

buildHeapの複雑さのためのTaylorシリーズ

これらの各ステップが機能する理由がわからない場合は、ここにプロセスの正当性を言葉で説明します。

  • 項はすべて正であるため、有限の合計は無限の合計よりも小さくなければなりません。
  • 級数は、x = 1/2で評価されるべき級数に等しくなります。
  • そのべき級数は、f(x)= 1 /(1-x)のテイラー級数の導関数に(一定時間)等しくなります。
  • x = 1/2は、そのテイラー級数の収束の範囲内です。
  • したがって、テイラー級数を1 /(1-x)に置き換え、微分し、評価して、無限級数の値を見つけることができます。

無限和は正確にnであるため、有限和はそれ以上大きくなく、したがってO(n)であると結論付けます。

ヒープのソートにO(n log n)の時間が必要なのはなぜですか?

buildHeap線形時間で実行できる場合、ヒープのソートにO(n log n)時間を必要とするのはなぜですか?ヒープのソートは2つの段階で構成されています。まず、buildHeap配列を呼び出します。最適に実装されている場合、O(n)時間を必要とします。次の段階は、ヒープ内の最大の項目を繰り返し削除して、配列の最後に配置することです。ヒープからアイテムを削除するため、ヒープの終わりの直後に、アイテムを格納できるオープンスポットが常にあります。したがって、ヒープソートは、次に大きいアイテムを連続的に削除し、最後の位置から開始して前に向かって配列に配置することで、ソートされた順序を実現します。ヒープのソートで支配的なのは、この最後の部分の複雑さです。ループは次のようになります。

for (i = n - 1; i > 0; i--) {
    arr[i] = deleteMax();
}

明らかに、ループはO(n)回実行されます(正確にはn-1、最後の項目は既に配置されています)。deleteMaxヒープの複雑さはO(log n)です。これは通常、ルート(ヒープ内に残っている最大のアイテム)を削除し、それをヒープ内の最後のアイテム(リーフ)に置き換えることによって実装されるため、最小のアイテムの1つになります。この新しいルートはほぼ確実にヒーププロパティに違反するためsiftDown、許容可能な位置に戻すまで呼び出す必要があります。これには、次に大きいアイテムをルートまで移動する効果もあります。buildHeapほとんどのノードでsiftDownツリーの下部から呼び出しているのとは対照的に、siftDown各反復でツリーの上部から呼び出していることに注意してください。ツリーは収縮していますが、十分に速くは収縮していません。ノードの前半を削除するまで(最下層を完全に取り除くと)、ツリーの高さは一定のままです。次の四半期の高さはh-1です。したがって、この第2ステージの総作業は

h*n/2 + (h-1)*n/4 + ... + 0 * 1.

スイッチに注意してください。今度はゼロの作業ケースが単一のノードに対応し、hの作業ケースがノードの半分に対応します。この合計はO(n log n)でありbuildHeap、siftUpを使用して実装された非効率なバージョンと同じです。しかし、この場合は、ソートしようとしているため、次に選択できるアイテムはありません。次に大きいアイテムを次に削除する必要があります。

要約すると、ヒープの並べ替えの作業は、2つの段階の合計です: buildHeapのO(n)時間と各ノードを順番に削除するO(n log n)なので、複雑度はO(n log n)です。比較ベースの並べ替えの場合、とにかくO(n log n)が期待できる最高であることを情報理論のいくつかのアイデアを使用して)証明できるため、これに失望したり、ヒープの並べ替えを期待して理由を達成したりする必要はありません。 O(n)時間制限buildHeap


2
他のほとんどの人がそれを参照しているようで、ヒープのソートには最良の選択であるため、最大ヒープを使用するように私の回答を編集しました。
Jeremy West

28
これにより、直感的にわかりやすくなりました。「1つのノードだけが上にあり、半分のノードが下のレイヤーにあるので、すべてのノードに操作を適用する必要がある場合、 siftUpよりもsiftDownを優先します。」
Vicky Chijwani 14

3
@JeremyWest「1つはヒープの先頭(配列の先頭)から開始し、各アイテムでsiftUpを呼び出すことです。」-ヒープの一番下から始めるつもりですか?
aste123

4
@ aste123いいえ、書かれているとおりです。アイデアは、ヒーププロパティを満たす配列の部分と、配列のソートされていない部分との間のバリアを維持することです。最初に前方に移動siftUpして各項目を呼び出すか、最後に後方に移動してを呼び出しsiftDownます。どちらの方法を選択しても、配列の並べ替えられていない部分の次の項目を選択し、適切な操作を実行して配列の順序付けられた部分の有効な位置に移動します。唯一の違いはパフォーマンスです。
ジェレミーウェスト

2
これは私が今まで見た中で、世界のどの質問に対しても最高の答えです。それはとてもよく説明されました、本当にそれは本当に可能であるようでした...どうもありがとう
HARSHIL JAIN

314

あなたの分析は正しいです。ただし、タイトではありません。

ヒープの構築が線形操作である理由を説明するのは簡単ではありません。よく読んでください。

偉大な解析アルゴリズムのを見ることができるここに


主な考え方は、build_heapアルゴリズムでは実際のheapifyコストがO(log n)すべての要素にかかるわけではないということです。

heapifyが呼び出されたときの実行時間は、プロセスが終了するまでに要素がツリー内でどれだけ下に移動するかによって異なります。つまり、ヒープ内の要素の高さに依存します。最悪の場合、要素はリーフレベルまでずっと下がることがあります。

レベルごとに行われた作業をカウントしてみましょう。

最下位レベルには2^(h)ノードがありますがheapify、これらのいずれも呼び出さないため、作業は0です。次のレベルには2^(h − 1)ノードがあり、それぞれが1レベル下に移動する可能性があります。下から3番目のレベルには2^(h − 2)ノードがあり、それぞれが2レベル下に移動する場合があります。

すべてのheapifyオペレーションがそうであるとは限らないのでO(log n)、これがあなたが得ている理由ですO(n)


17
これはすばらしい説明ですが、なぜヒープソートがO(n log n)で実行されるのですか。同じ理由がヒープソートに適用されないのはなぜですか?
hba 2013年

49
@hba私の質問への答えは、この記事のこの画像を理解することにあると思います。 で完了したときですが、で完了したときです。したがって、実際のソート(ヒープからアイテムを1つずつプルする)は、で行う必要があります。HeapifyO(n)siftDownO(n log n)siftUpsiftUpO(n log n)
The111

3
一番下にある外部ドキュメントの直感的な説明が本当に気に入っています。
Lukas Greblikas 2013年

1
@hbaジェレミー・ウェストによる以下の回答は、より細かく、理解しやすい詳細で質問に対処し、ここでThe111のコメント回答をさらに説明します。
cellepo 2015年

質問。i高さhのツリーの最下部から高さのノードに対して行われた#比較2* log(h-i)も同様に比較を行う必要があり、@ The111も考慮する必要があるようです。どう思いますか?
2016年

94

直感的に:

「複雑さはO(nLog n)である必要があります...「ヒープ化」する各アイテムについて、これまでのヒープの各レベル(log nレベル)に対して一度フィルターをかける必要がある可能性があります。」

結構です。あなたのロジックはタイトなバウンドを生成しません-それは各ヒープ化の複雑さを過大評価します。ボトムアップで構築した場合、挿入(ヒープ化)はをはるかに下回ることがありO(log(n))ます。プロセスは次のとおりです。

(手順1) 最初のn/2要素はヒープの一番下の行に配置されます。h=0、heapifyは必要ありません。

(手順2) 次の要素は、下から1行目に配置されます。、ヒープ化フィルターは1レベル下にあります。n/22h=1

(ステップi 次の要素は下から上に並んでいきます。、フィルターレベルをheapify します。n/2iih=ii

(Step log(n) 最後の要素は下から上に並んでいます。、フィルターレベルをheapify します。n/2log2(n) = 1log(n)h=log(n)log(n)

注意:ステップ1の後1/2、要素(n/2)は既にヒープ内にあり、一度heapifyを呼び出す必要すらありませんでした。また、1つの要素(ルート)だけが実際に完全なlog(n)複雑さを招くことにも注意してください。


理論的には:

Nサイズのヒープを構築するための合計手順はn、数学的に書き出すことができます。

高さiでは、heapifyを呼び出す必要のある要素があることを(上で)示しましたが、heapify at height はであることがわかっています。これは与える:n/2i+1iO(i)

ここに画像の説明を入力してください

最後の総和の解は、よく知られた幾何級数方程式の両側の導関数を取ることによって見つけることができます。

ここに画像の説明を入力してください

最後x = 1/2に、上記の方程式にプラグインすると、が得られ2ます。これを最初の方程式に代入すると、次のようになります。

ここに画像の説明を入力してください

したがって、ステップの総数は O(n)


35

要素を繰り返し挿入してヒープを構築した場合は、O(n log n)になります。ただし、要素を任意の順序で挿入し、アルゴリズムを適用してそれらを適切な順序に「ヒープ化」することにより、新しいヒープをより効率的に作成できます(もちろん、ヒープのタイプによって異なります)。

例については、http://en.wikipedia.org/wiki/Binary_heap、「ヒープの構築」を参照してください。この場合、基本的にツリーの最下位レベルから作業を進め、ヒープ条件が満たされるまで親ノードと子ノードを交換します。


12

すでにいくつかの素晴らしい答えがありますが、少し視覚的な説明を追加したいと思います

ここに画像の説明を入力してください

今、画像を見て、ある
n/2^1 緑色のノードとの高さ0(ここで2分の23 = 12)
n/2^2 の赤色のノード高さ1(ここでは4分の23 = 6)
n/2^3 ブルーノード高さ2(ここで23/8 = 3)
n/2^4 紫色のノード高さ3(ここでは16分の23 = 2)
があるので、n/2^(h+1)高さのため、ノードH
複雑さをカウントすることができます時間を見つけるために行われた仕事の量反復の最大無いが行われ、各ノードが
、今では、各ノードできることに気づいたことができます実行(最大)反復==ノードの高さ

Green  = n/2^1 * 0 (no iterations since no children)  
red    = n/2^2 * 1 (heapify will perform atmost one swap for each red node)  
blue   = n/2^3 * 2 (heapify will perform atmost two swaps for each blue node)  
purple = n/2^4 * 3 (heapify will perform atmost three swaps for each purple node)   

したがって、高さがhのノードの場合、実行される最大の作業はn / 2 ^(h + 1)* hです。

今、行われる総作業は

->(n/2^1 * 0) + (n/2^2 * 1)+ (n/2^3 * 2) + (n/2^4 * 3) +...+ (n/2^(h+1) * h)  
-> n * ( 0 + 1/4 + 2/8 + 3/16 +...+ h/2^(h+1) ) 

ここで、hの任意の値について、シーケンス

-> ( 0 + 1/4 + 2/8 + 3/16 +...+ h/2^(h+1) ) 


したがって、 1を超えることはありません。したがって、ヒープを構築するための時間の複雑さは O(n)を超えることはありません。


7

我々は、ヒープの高さを知っているように、ログ(N) elements.Letsの総数はとして表現されているN、H
   我々はheapify操作を実行すると、最後のレベル(AT要素hが)も単一の移動はありませんステップ。
   最後から2番目のレベル(h-1)の要素の数は2 h-1で、最大1レベル(ヒープ化中)に移動できます。
   同様に、i 番目のレベルにはhiの位置に移動できる2つのi要素があります。

したがって、移動の総数= S = 2 h * 0 + 2 h-1 * 1 + 2 h-2 * 2 + ... 2 0 * h

                                               S = 2 h {1/2 + 2/2 2 + 3/2 3 + ... h / 2 h } ----------------------- -------------------------- 1
これはAGPシリーズです。これを解決するには、両側を2
                                               S / 2 = 2 hで 除算します{1/2 2 + 2/2 3 + ... h / 2 h + 1 } --------------------------------- ---------------- 2 1から
2を引くと、S / 2 = 2 h { 1/2 + 1/2 2 + 1/2 3 + ... + 1 / 2 時間 + h / 2 時間+ 1 }
                                               
                                               S = 2 H + 1 {1/2 + 1/2 2 + 1/2 3 + ... + 1/2 H + H / 2 H + 1 }
1/2 + 1/2 2 + 1/2 3 + ... + 1/2 hは、合計が1未満のGPの減少です(hが無限大になる傾向がある場合、合計は1になる傾向があります)。さらなる分析では、上部1である和に結合者がみましょう 。これは、得られるS = 2 H + 1 {1 + H / 2 H + 1 }                     = 2 、H + 1つの + H 〜2 H + HとしてH =ログを(n)2 時間 = n


                    


したがって、S = n + log(n)
T(C)= O(n)


6

ヒープを構築しているときに、ボトムアップのアプローチを取っているとしましょう。

  1. 各要素を取得してその子と比較し、ペアがヒープルールに準拠しているかどうかを確認します。したがって、したがって、葉は無料でヒープに含まれます。子供がいないからです。
  2. 上に移動すると、葉の真上のノードの最悪のシナリオは1つの比較になります(最大で、1世代の子とのみ比較されます)。
  3. さらに上に行くと、直接の親は最大で2世代の子​​供と比較できます。
  4. 同じ方向を続けると、最悪のシナリオでルートのlog(n)比較が行われます。そして、その直接の子供のためのlog(n)-1、それらの直接の子供のためのlog(n)-2など。
  5. まとめると、log(n)+ {log(n)-1} * 2 + {log(n)-2} * 4 + ..... + 1 * 2 ^ {( logn)-1} O(n)にすぎません。

2

ヒープを構築する場合、高さlogn -1(ここで、lognはn要素のツリーの高さ)から始めます 。高さ「h」にある各要素について、最大(logn -h)の高さまで下げます。

    So total number of traversal would be:-
    T(n) = sigma((2^(logn-h))*h) where h varies from 1 to logn
    T(n) = n((1/2)+(2/4)+(3/8)+.....+(logn/(2^logn)))
    T(n) = n*(sigma(x/(2^x))) where x varies from 1 to logn
     and according to the [sources][1]
    function in the bracket approaches to 2 at infinity.
    Hence T(n) ~ O(n)

1

連続挿入は次のように説明できます。

T = O(log(1) + log(2) + .. + log(n)) = O(log(n!))

n! =~ O(n^(n + O(1)))したがって、スターリング近似により、T =~ O(nlog(n))

これが役立つことを願って、最適な方法O(n)は、特定のセットのビルドヒープアルゴリズムを使用することです(順序は関係ありません)。


1

基本的に、ヒープを構築している間、作業はリーフ以外のノードでのみ行われます...そして行われる作業は、ヒープ条件を満たすスワップダウンの量です...つまり、(最悪の場合)量は高さに比例しますノードの...すべての問題の複雑さは、すべての非リーフノードの高さの合計に比例します。つまり、(2 ^ h + 1-1)-h-1 = nh-1 =オン)


1

@bcorsoは、複雑性分析の証明をすでに示しています。しかし、まだ複雑さの分析を学習している人のために、これを追加します:

元の間違いの根拠は、「ヒープへの挿入にはO(log n)時間かかる」というステートメントの意味の誤解によるものです。ヒープへの挿入は確かにO(log n)ですが、nは挿入時のヒープのサイズであることを認識する必要があります。

n個のオブジェクトをヒープに挿入する場合、i番目の挿入の複雑さはO(log n_i)です。ここで、n_iは挿入i時のヒープのサイズです。最後の挿入だけがO(log n)の複雑さを持っています。


1

あなたが持っていると仮定しましょNのヒープ内の要素を。次に、その高さはLog(N)になります

今、あなたは複雑のようになり、別の要素を挿入したい:ログ(N) 、我々はすべての方法を比較する必要がUPルートに。

これで、N + 1個の要素と高さ= Log(N + 1)が得られました

誘導技術を使用すると、挿入の複雑さが∑logiであることが証明できます。

現在使用しています

ログa +ログb =ログab

これにより、次のように簡略化されます:∑logi = log(n!)

これは実際にはO(NlogN)です

だが

私たちはここで何か間違っているのです。したがって、ほとんどの場合実行中に、ツリーを途中まで上ることはありません。そこから、上記の回答で与えられた数学を使用することにより、この境界を最適化して別のより厳しい境界を設定できます。

この実現は、詳細とヒープの実験の後に私に起こりました。


0

私はジェレミー・ウェストの説明が本当に好きです...本当に理解しやすい別のアプローチがここにあり ますhttp://courses.washington.edu/css343/zander/NotesProbs/heapcomplexity

なぜなら、buildheapはheapifyに依存して使用し、shiftdownアプローチはすべてのノードの高さの合計に依存して使用されるためです。したがって、S =(2 ^ i *(hi))のi = 0からi = hまでの合計で与えられるノードの高さの合計を見つけるには、h = lognはsを解く木の高さです。 s = 2 ^(h + 1)-1-(h + 1)、n = 2 ^(h + 1)-1 s = n-h-1 = n- logn-1 s = O(n)、ビルドヒープの複雑さはO(n)です。


0

「ビルドヒープの線形時間範囲は、ヒープ内のすべてのノードの高さの合計を計算することによって表示できます。これは、破線の最大数です。N= 2 ^( h + 1)– 1ノード、ノードの高さの合計はN – H – 1なので、O(N)です。 "


0

O(n)の証明

証明は空想的ではなく、非常に簡単です。完全なバイナリツリーの場合のみを証明しました。結果は完全なバイナリツリーに一般化できます。


0

各ノードが実行できる最大の移動を計算することにより、ヒープビルドのランタイムを取得します。したがって、各行にあるノードの数と、各ノードがノードからどれだけ離れることができるかを知る必要があります。

ルートノードから開始すると、次の各行は前の行の2倍のノードを持っているので、ノードの数がなくなるまでノードの数を2倍にできるかという質問に答えることで、ツリーの高さを取得します。または数学的には、ツリーの高さはlog2(n)です。nは配列の長さです。

後ろから始まる1つの行のノードを計算するには、n / 2ノードが一番下にあることを知っているため、2で割ると、前の行が得られます。

これに基づいて、シフトダウンアプローチの次の式を取得します:(0 * n / 2)+(1 * n / 4)+(2 * n / 8)+ ... +(log2(n)* 1)

最後の括弧内の項は、ツリーの高さにルートにある1つのノードを掛けたものであり、最初の括弧内の項は、最下行のすべてのノードにそれらが移動できる長さを掛けたものです。スマートの同じ式: ここに画像の説明を入力してください

数学

nを戻すと、2 * nが得られます。2は定数であり、Siftdownアプローチの最悪の場合の実行時間があるため、破棄できます:n。


-6

あなたは間違いを犯していると思います。これを見てくださいhttp : //golang.org/pkg/container/heap/ヒープの構築はO(n)ではありません。ただし、挿入はO(lg(n)です。ヒープサイズb / cを設定した場合、ヒープは領域を割り当ててデータ構造を設定する必要があるため、初期化はO(n)であると想定しています。ヒープに挿入してはい、各挿入はlg(n)であり、n個の項目があるため、uが述べたようにn * lg(n)を取得します


2
いいえ、タイトではありません。
ビルドヒープの

それは推定であるように見えます。彼が参照した記事の引用は「直感はheapifyの呼び出しのほとんどが非常に短いヒープ上にあるということです」しかし、これはいくつかの仮定を行っています。おそらく、大きなヒープの場合、たとえ通常O(n)に近づくことができたとしても、最悪のシナリオは依然としてO(n * lg(n))です。しかし、私は間違っている可能性があります
マイクシャクター2012年

はい、それも私の直感的な答えですが、ウィキペディアなどの参照では、「n要素のヒープはO(n)でボトムアップで構築できる」と述べています。
GBa 2012年

1
完全にソートされたデータ構造を考えていました。ヒープの特定のプロパティを忘れました。
Mike Schachter
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.