🦁

ヒープの実装

2024/10/27に公開

Complete Binary Tree

n = int(input())

A = [0] + list(map(int,input().split()))

def left(i):
    return A[2*i]

def right(i):
    return A[2*i+1]

def parent(i):
    return A[i//2]

def print_node(i):
    print("node %d: key = %d, " % (i,A[i]), end = "")
    if i//2 >= 1:
        print("parent key = %d, " %parent(i), end = "")
    if 2*i < len(A):
        print("left key = %d, " %left(i), end = "")
    if 2*i + 1 < len(A):
        print("right key = %d, " %right(i), end = "")

for i in range(1, len(A)):
    print_node(i)
    print()

Maximum Heap

H = int(input())
A = [None] + list(map(int,input().split()))

def left(i):
    return 2*i

def right(i):
    return 2*i+1

def parent(i):
    return i//2

def maxHeapify(A,i): #節点iを根とする部分木(i以下の木)がマックスヒープになるように設計する。大きいやつをただ上に持ってきているだけ。
    l = left(i)
    r = right(i)
    #左の子、自分、右の子で値が最大のノードを選ぶ。
    if l <= H and A[l]>A[i]:
        largest = l
    else:
        largest = i
    if r <= H and A[r]>A[largest]:
        largest = r
    if largest != i: #iの子の方が値が大きい場合交換
        A[i],A[largest] = A[largest],A[i]
        maxHeapify(A,largest) #再帰呼び出し

def buildMaxHeap(A): #H//2がラストのノードの親。
    for i in range(H//2,0,-1): #後ろからやっていかないとダメ。頭からやっていたら最後の方に大きいやつがある時に、上に来れない。
        maxHeapify(A,i)
buildMaxHeap(A)
print("",*A[1:])

Priority Queue

def left(i):
    return 2*i

def right(i):
    return 2*i+1

def parent(i):
    return i//2

A = [0]*2000000
H = 0

def maxheapify(S,i): #これの計算量は木の高さに依存するのでO(logH)
     #これはノードiより下のノードはmaxheap条件を満たしているが、ノードiの子供たちとの条件を満たしていない時に使う。
    l = left(i)
    r = right(i)
    global H
    if l <= H and S[i] < S[l]:
        largest = l
    else:
        largest = i
    if r <= H and S[largest] < S[r]:
        largest = r
    if largest != i:
        S[largest],S[i] = S[i],S[largest]
        maxheapify(S,largest)

    
def heapIncreaseKey(A,i,key): #buildする必要ない。親との大小関係を確認するだけでいい。
    if key < A[i]: #必要ぽい。#新しい値<古い値だったら これはそういう仮定
        return
    A[i] = key
    #max heap条件を成立させる。
    while i > 1 and A[parent(i)] < A[i]: #ヒープにおいて左の子と右の子の大小は気にしない。
        A[i],A[parent(i)] = A[parent(i)],A[i]
        i = parent(i)
    
def heapInsert(k):
    global H,A
    H += 1
    A[H] = -1 #新しいキーの値を-1にする。もしA[H]に既に値が入っていたら(ヒープの操作ではextractの時に削除したりしない。)
    heapIncreaseKey(A,H,k)
    
def heapExtractMax(A):
    global H
    if H < 1: #何も入っていないのに入れようとしちゃだめ
        return
    max = A[1]
    A[1] = A[H] #最後のを持ってきて、
    H -= 1
    maxheapify(A,1) #これで十分。root以外はmaxheap条件を満たしているから。
    return max

while True:
    a = input().split()
    if a[0] == "insert":
        heapInsert(int(a[1])) #文字列だと不等号が動かない。
    elif a[0] == "extract":
        print(heapExtractMax(A)) #これだとO(H)だけかかるので全然早くない。
    else:
        break

Discussion