web-dev-qa-db-ja.com

最大ヒープのK番目に大きい要素

私は以下を解決するために何かを考え出そうとしています:

配列として表される最大ヒープを指定すると、ヒープを変更せずにk番目に大きい要素を返します。線形時間で実行するように依頼されましたが、ログ時間で実行できると言われました。

私は解決策を考えました:

2番目のmax-heapを使用して、kまたはk + 1の値をそこに入力し(最初の幅への最初のトラバース)、k要素をポップして、目的の要素を取得します。これはO(N + logN)= O(N)である必要があると思います

おそらくO(logN)時間内に、より良い解決策がありますか?

15
Alstor

Max-heapには多くの方法があり、より良いケースは完全にソートされた配列であり、他の極端なケースでは、ヒープは完全に非対称の構造を持つことができます。

これはこれを見ることができます: enter image description here

最初のケースでは、k番目に最も大きい要素がk番目の位置にあり、ヒープの配列表現を使用してO(1)で計算できます。ただし、通常、次のことを確認する必要があります。 (k、2k)要素間、およびそれらを並べ替える(または別のヒープで部分的に並べ替える)私が知る限り、これはO(K・log(k))です。

そしてアルゴリズム:

Input:
    Integer kth <- 8
    Heap heap <- {19,18,10,17,14,9,4,16,15,13,12}

BEGIN
    Heap positionHeap <- Heap with comparation: ((n0,n1)->compare(heap[n1], heap[n0]))

    Integer childPosition
    Integer candidatePosition <- 0
    Integer count <- 0
    positionHeap.Push(candidate)
    WHILE (count < kth) DO
        candidatePosition <- positionHeap.pop();
        childPosition <- candidatePosition * 2 + 1
        IF (childPosition < size(heap)) THEN
            positionHeap.Push(childPosition)
            childPosition <- childPosition + 1
            IF (childPosition < size(heap)) THEN
                positionHeap.Push(childPosition)
            END-IF
        END-IF
        count <- count + 1
    END-WHILE
    print heap[candidate]
END-BEGIN

編集済み

私はここでフレデリクソンによる「最小ヒープでの選択の最適アルゴリズム」を見つけました: ftp://paranoidbits.com/ebooks/An%20Optimal%20Algorithm%20for%20Selection%20in%20a%20Min-Heap.pdf

いいえ、単純なセルプローブの下限によるO(log n)時間アルゴリズムはありません。 kが(一般性を失うことなく)2のべき乗であり、ヒープが次のようになっているとします(ラベルを付けるのは簡単ですが、実際の違いはありません)

      1
   2     3
  4 5   6 7
.............
permutation of [k, 2k).

最悪の場合、ヒープによって課せられる順序関係がなく、kが見つからない限り、まだ調べられていない任意の場所にある可能性があるため、順列全体を読み取る必要があります。これにはOmega(k)がかかり、templatetypedefによって投稿された(複雑な!)アルゴリズムと一致します。

4
David Eisenstat

私の知る限り、この問題を解決するための簡単なアルゴリズムはありません。私が知っている最良のアルゴリズムはフレデリクソンによるもので、簡単ではありません。あなたは紙をチェックすることができます ここでは、それはペイウォールの後ろにあるかもしれません。 時間内に実行されますO(k)そしてこれは可能な限り最高の時間であると主張されていますなので、ログタイムソリューションは存在しないと思います。

これよりも良いアルゴリズムを見つけた場合は、必ずお知らせします。

お役に立てれば!

2
templatetypedef

配列の最大ヒープ:element at i is larger than elements at 2*i+1 and 2*i+2iは0ベース)

別の最大ヒープ(insertpopempty)と、要素ペア(value, index)valueでソートされたものが必要です。疑似コード(境界チェックなし):

input: k
1. insert (at(0), 0)
2. (v, i) <- pop and k <- k - 1
3. if k == 0 return v
4. insert (at(2*i+1), 2*i+1) and insert (at(2*+2), 2*+2)
5. goto 2

ランタイム評価

  • (i)での配列アクセス:O(1)
  • ヒープへの挿入:O(log n)
  • ペアのヒープのサイズは最大でk + 1であるため、4で挿入すると最大でlog(k)かかります。
  • ステートメント3.最大でk回到達する
  • 合計ランタイム:O(k log k)
1
BeyelerStudios