それは最大ヒープですか?


14

ヒープも優先キューとして知られているが、抽象データ型です。概念的には、すべてのノードの子がノード自体以下であるバイナリツリーです。(最大ヒープと仮定します。)要素がプッシュまたはポップされると、ヒープはそれ自体を再配置し、最大の要素が次にポップされるようにします。ツリーまたは配列として簡単に実装できます。

受け入れを選択した場合の課題は、アレイが有効なヒープかどうかを判断することです。すべての要素の子が要素自体以下の場合、配列はヒープ形式になります。例として次の配列を取り上げます。

[90, 15, 10, 7, 12, 2]

本当に、これは配列の形に配置された二分木です。これは、すべての要素に子があるためです。90には、15と10の2つの子があります。

       15, 10,
[(90),         7, 12, 2]

15には子もあり、7と12:

               7, 12,
[90, (15), 10,        2]

10には子供がいます:

                      2
[90, 15, (10), 7, 12,  ]

次の要素も10の子になりますが、スペースがないことを除きます。配列が十分に長ければ、7、12、および2にもすべて子があります。ヒープの別の例を次に示します。

[16, 14, 10, 8, 7, 9, 3, 2, 4, 1]

そして、これは前の配列が作るツリーの視覚化です:

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

これが十分に明確でない場合に備えて、i番目の要素の子を取得するための明示的な式を次に示します

//0-indexing:
child1 = (i * 2) + 1
child2 = (i * 2) + 2

//1-indexing:
child1 = (i * 2)
child2 = (i * 2) + 1

空でない配列を入力として受け取り、配列がヒープ順であれば真の値を出力し、そうでなければ偽の値を出力する必要があります。これは、プログラム/関数が予期する形式を指定する限り、0インデックス付きヒープ、または1インデックス付きヒープになります。すべての配列に正の整数のみが含まれると想定できます。ヒープ組み込み使用できません。これには以下が含まれますが、これらに限定されません

  • 配列がヒープ形式かどうかを判断する関数
  • 配列をヒープまたはヒープ形式に変換する関数
  • 入力として配列を受け取り、ヒープデータ構造を返す関数

このpythonスクリプトを使用して、配列がヒープ形式であるかどうか(0インデックス)を確認できます。

def is_heap(l):
    for head in range(0, len(l)):
        c1, c2 = head * 2 + 1, head * 2 + 2
        if c1 < len(l) and l[head] < l[c1]:
            return False
        if c2 < len(l) and l[head] < l[c2]:
            return False

    return True

テストIO:

これらの入力はすべてTrueを返す必要があります。

[90, 15, 10, 7, 12, 2]
[93, 15, 87, 7, 15, 5]
[16, 14, 10, 8, 7, 9, 3, 2, 4, 1]
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
[100, 19, 36, 17, 3, 25, 1, 2, 7]
[5, 5, 5, 5, 5, 5, 5, 5]

そして、これらの入力はすべてFalseを返す必要があります。

[4, 5, 5, 5, 5, 5, 5, 5]
[90, 15, 10, 7, 12, 11]
[1, 2, 3, 4, 5]
[4, 8, 15, 16, 23, 42]
[2, 1, 3]

いつものように、これはコードゴルフなので、標準的な抜け穴が適用され、バイト単位の最短回答が勝ちます!



繰り返される要素がある場合、この定義に従ってヒープを形成することは不可能かもしれないことは正しいですか?
feersum

@feersumどう[3, 2, 1, 1]ですか?
ニール

@feersumそれは素晴らしい点です、私はそれを考えていませんでした。ヒープの説明を更新し、要素が重複する例を追加しました。ありがとうございました!
DJMcMayhem

5
ヒープは、優先キューとも呼ばれません。優先度キューは抽象データ型です。ヒープは、優先度キューを実装するために使用されることがあるデータ構造です(ヒープ自体は、さらに基本的なデータ構造の上に実装されますが、それは重要です)。優先キューは、リンクリストなどの他のデータ構造の上に実装できます。
リンドンホワイト

回答:


7

ゼリー、 11 9 5バイト

x2:ḊṂ

Dennisのおかげで4バイトが削除されました!

ここで試してみてください。

説明

x2          Duplicate each element.
:Ḋ          Each element divided by the input with the first element removed,
            as integer, so there is a 0 only if some element in the duplicated
            list is less than the corresponding element in the other.
            There are also elements left unchanged, but it doesn't matter as
            the input is all positive.
Ṃ           Minimum in the list.

10

JavaScript(ES6)、34 30バイト

a=>!a.some((e,i)=>e>a[i-1>>1])

編集:仕様の明確化のために私のコードを修正するには1バイトかかるので、4バイトを節約してくれた@ edc65に感謝します。


テストケース2 [93, 15, 87, 7, 15, 5]と6 が失敗します[5, 5, 5, 5, 5, 5, 5, 5]
-edc65

これはより適切に機能し、3文字短くなりますa=>!a.some((e,i)=>e>a[i-1>>1])
-edc65

1
@ edc65これらのテストケースは、回答を書いた後に追加されました。
ニール


4

J、24バイト

*/@:<:]{~0}:@,<.@-:@i.@#

説明

*/@:<:]{~0}:@,<.@-:@i.@#  Input: s
                       #  Count of s
                    i.@   Create range [0, 1, ..., len(s)-1]
                 -:@      Halve each
              <.@         Floor each
         0   ,            Prepend a zero to it
          }:@             Remove the last value to get the parent indices of each
      ]                   Identity function to get s
       {~                 Take the values from s at the parent indices
    <:                    For each, 1 if it is less than or equal to its parent else 0
*/@:                      Reduce using multiplication and return

3

MATL13 12バイト

ttf2/k)>~4L)

オンラインでお試しください!または、すべてのテストケースを確認します

配列が空でなく、そのエントリがすべてゼロでない場合、配列は真実です。それ以外の場合は偽です。以下に例を示します。

説明

t     % Take input implicitly. Duplicate
tf    % Duplicate and push indices of nonzero entries. This gives [1 2 ... n] where n
      % is input size
2/k   % Divide by 2 and round down
)     % Index into input. Gives array of parents, except for the first entry
>~    % True for entries of the input that don't exceed those in the array of parents
4L)   % Discard first entry

2

Python 2、45バイト

f=lambda l:l==[]or l[len(l)/2-1]/l.pop()*f(l)

Falsyの場合は0、Truthyの場合は0以外を出力します。

最後の要素がindexの親以下であることを確認しますlen(l)/2-1。次に、再帰を繰り返して、リストの最後の要素が削除された同じものがTrueであることを確認し、リストが空になるまで繰り返します。


48バイト:

f=lambda l,i=1:l==l[:i]or l[~-i/2]/l[i]*f(l,i+1)

各インデックスiで、要素が最大でindexの親であることを確認します(i-1)/2。そうでない場合、floor-divisionは0を生成します。

基本ケースをi/len(l)or行うと、同じ長さが得られます。最初はzip圧縮を試みましたが、より長いコード(57バイト)を取得しました。

lambda l:all(map(lambda a,b,c:b<=a>=c,l,l[1::2],l[2::2]))

1

R、97 88 82バイト

うまくいけば、これを正しく理解できました。次に、さらにバイトを削除できるかどうかを確認します。rbindを捨て、sapplyを入れて、1ベースのベクトルを適切に処理します。

名前のない関数として実装

function(Y)all(sapply(1:length(Y),function(X)Y[X]>=Y[X*2]&Y[X]>=Y[X*2+1]),na.rm=T)

いくつかのテストケースで

> f=
+ function(Y)all(sapply(1:length(Y),function(X)Y[X]>=Y[X*2]&Y[X]>=Y[X*2+1]),na.rm=T)
> f(c(90, 15, 10, 7, 12, 2))
[1] TRUE
> f(c(93, 15, 87, 7, 15, 5))
[1] TRUE
> f(c(10, 9, 8, 7, 6, 5, 4, 3, 2, 1))
[1] TRUE
> f(c(5, 5, 5, 5, 5, 5, 5, 5))
[1] TRUE
> f(c(4, 5, 5, 5, 5, 5, 5, 5))
[1] FALSE
> f(c(90, 15, 10, 7, 12, 11))
[1] FALSE
> f(c(4, 8, 15, 16, 23, 42))
[1] FALSE

seq(Y)代わりに使用できます1:length(Y)
rturnbull




0

C ++ 14、 134の 105バイト

#define M(d) (2*i+d<c.size()&&(c[i]<c[2*i+d]||f(c,2*i+d)==0))
int f(auto&c,int i=0){return!(M(1)||M(2));}

が必要です c容器支持すること.operator[](int).size()、のようにstd::vector<int>

ゴルフをしていない:

int f(auto& c, int i=0) {
    if (2*i+1<c.size() && c[i] < c[2*i+1]) return 0;
    if (2*i+2<c.size() && c[i] < c[2*i+2]) return 0;
    if (2*i+1<c.size() && (f(c,2*i+1) == 0)) return 0;
    if (2*i+2<c.size() && (f(c,2*i+2) == 0)) return 0;
    return 1;
}

truthy = 0およびfalsy = 1が許可される場合は、より小さい可能性があります。


0

R、72バイト

他のR回答とは少し異なるアプローチ。

x=scan();all(diff(x[c(a<-1:(N<-sum(1|x)),a,a*2,a*2+1)],l=N*2)<1,na.rm=T)

stdinから入力を読み取り、すべての比較ペアのベクトルを作成し、それらを互いに減算し、結果が負の数またはゼロであることを確認します。

説明

stdinから入力を読み取ります。

x=scan();

ペアを作成します。親ノードのインデックス1...NNの長さx)を作成します。各親には(最大で)2つの子があるため、これを2回使用します。我々はまた、子供を取る、(1...N)*2(1...N)*2+1。の長さを超えるインデックスの場合x、RはNA「使用不可」を返します。入力については90 15 10 7 12 2、このコードは私たちに与え90 15 10 7 12 2 90 15 10 7 12 2 15 7 2 NA NA NA 10 12 NA NA NA NAます。

                  x[c(a<-1:(N<-sum(1|x)),a,a*2,a*2+1)]

このペアのベクトルでは、各要素はN*2離れた距離にパートナーを持っています。たとえば、アイテム1のパートナーは位置12(6 * 2)にあります。我々は使用diffを指定して、これらのペアの間の差を計算するためにlag=N*2、正しい相手にアイテムを比較します。NA要素に対する操作は、単に戻りNAます。

             diff(x[c(a<-1:(N<-sum(1|x)),a,a*2,a*2+1)],l=N*2)

最後に、これらの戻り値がすべてより小さいことを確認します1(つまり、最初の数値(親)が2番目の数値(子)よりも大きい)NA

         all(diff(x[c(a<-1:(N<-sum(1|x)),a,a*2,a*2+1)],l=N*2)<1,na.rm=T)

0

実は、16バイト

この回答は、jimmy23013のJelly answerに基づいています。ゴルフの提案を歓迎します!オンラインでお試しください!

;;2╟┬Σ1(tZ`i<`Mm

アンゴルフ

         Implicit input a.
;;       Duplicate a twice.
2╟       Wrap two of the duplicates into a list.
┬        Transpose the duplicates.
Σ        Sum all of the columns to get a flat list like this:
           [a_0, a_0, a_1, a_1, ..., a_n, a_n]
         This gets the parent nodes of the heap.
1(t      Get a[1:] using the remaining duplicate of a.
         This is a list of the child nodes of the heap.
Z`i<`M   Check if every child node is less than its parent node.
m        Get the minimum. This returns 1 if a is a max-heap, else 0.
         Implicit return.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.