PythonでのMinヒープデータ構造の実装方法を解説する

スポンサーリンク

今回は、Min Heap(Pythonではヒープキューと呼ばれています)について詳しく説明します。

Pythonのヒープとそのライブラリ関数(heapqモジュール)については既に学びました。

ここでは、ミニヒープとその実装について学び、さらに heapify, heappush, heappop 関数を自分自身で実装するための Python コードを見ていきます。

簡単に復習しておきましょう。

スポンサーリンク

Minヒープとは?

最小ヒープとは、完全な二分木(完全な二分木とは、最深部/最終レベルの右端ノードを除いて完全に埋まっている木)であり、各ノードはそのすべての子より小さいか等しくなっています。

したがって、ヒープのルートノードは最小の要素です。

ミニヒープのデータ構造は、一般に優先度待ち行列を表現するのに使われる。

import sys
 
#defining a class min_heap for the heap data structure
 
class min_heap:
    def __init__(self, sizelimit):
        self.sizelimit = sizelimit
        self.cur_size = 0
        self.Heap = [0]*(self.sizelimit + 1)
        self.Heap[0] = sys.maxsize * -1
        self.root = 1
 
 
    # helper function to swap the two given nodes of the heap
    # this function will be needed for heapify and insertion to swap nodes not in order
    def swapnodes(self, node1, node2):
        self.Heap[node1], self.Heap[node2] = self.Heap[node2], self.Heap[node1]
  
    # THE MIN_HEAPIFY FUNCTION
    def min_heapify(self, i):
  
        # If the node is a not a leaf node and is greater than any of its child
        if not (i >= (self.cur_size//2) and i <= self.cur_size):
            if (self.Heap[i] > self.Heap[2 * i]  or  self.Heap[i] > self.Heap[(2 * i) + 1]):
                if self.Heap[2 * i] < self.Heap[(2 * i) + 1]:
     # Swap the node with the left child and then call the min_heapify function on it
                    self.swapnodes(i, 2 * i)
                    self.min_heapify(2 * i)
  
                else:
                # Swap the node with right child and then call the min_heapify function on it
                    self.swapnodes(i, (2 * i) + 1)
                    self.min_heapify((2 * i) + 1)
  
 
 
    # THE HEAPPUSH FUNCTION
    def heappush(self, element):
        if self.cur_size >= self.sizelimit :
            return
        self.cur_size+= 1
        self.Heap[self.cur_size] = element
        current = self.cur_size
        while self.Heap[current] < self.Heap[current//2]:
            self.swapnodes(current, current//2)
            current = current//2
  
  
    # THE HEAPPOP FUNCTION
    def heappop(self):
        last = self.Heap[self.root]
        self.Heap[self.root] = self.Heap[self.cur_size]
        self.cur_size -= 1
        self.min_heapify(self.root)
        return last
  
  
    # THE BUILD_HEAP FUNCTION
    def build_heap(self):
        for i in range(self.cur_size//2, 0, -1):
            self.min_heapify(i)
  
  
    # helper function to print the heap
    def print_heap(self):
        for i in range(1, (self.cur_size//2)+1):
            print("Parent Node is "+ str(self.Heap[i])+" Left Child is "+ str(self.Heap[2 * i]) +                  " Right Child is "+ str(self.Heap[2 * i + 1]))
  
  
# Driver Code
minHeap = min_heap(10)
minHeap.heappush(15)
minHeap.heappush(7)
minHeap.heappush(9)
minHeap.heappush(4)
minHeap.heappush(13)
minHeap.print_heap()

H

Understanding the functions used in the implementation of Min Heap

1. min-heapify 関数

この関数は、あるノードとそのすべての子孫ノード(子ノードとその子)を ヒープ属性に従わせる。

ヒープの性質に従い、与えられたヒープがその部分木の最小ノードになるように、ノードをスワップして並べ替えます。

この関数は、まず、与えられたノードとその子供のうち、最も小さい値を持つノードを見つける。

そして、与えられたノード(iとする)を、見つかった最小値のノード(jとする)と交換し、ノードjに対して(再帰的に)min-heapify関数を呼び出す。

これにより、ノードjに割り当てられた新しい値が、その部分木のヒープ特性を破らないことが確認される。

この関数は、せいぜい木の深さまで走査しなければならないので、その時間計算量はO(d)(dは深さ、ノード数でいえばO(log n)、nはヒープ内の要素数)です。

2. ビルドヒープ関数

この関数は、任意のリスト(または他の任意の反復可能ファイル)からヒープを構築 します。

すなわち、リストを受け取り、ヒープ特性を満たすように各要素を並べ替 える。

これは、各ノードに対してmin-heapifyを繰り返し適用することにより、単純に実装することができます

この関数の時間計算量はO(n)であり、ここでnはヒープ内の要素数です。

3. ヒープポップ関数

この関数はヒープの最小値(ルート要素)をポップアウトします。

これは実際には、ルートノードと最後のノードを交換し、(最小値を含む)最後のノードを削除し、スワップによる変更後もヒープ特性を維持するように、ルートノードに対してmin-heapifyを呼び出すことによって行われる。

子孫を処理するだけなので、時間計算量はO(log n)(nは要素数)、またはO(h)(hは木の高さ)で、完全木であるためlog nとなります。

4. heappush関数

この関数は、新しい要素をヒープにプッシュし、ヒープのプロパティを維持したまま、正しい位置に配置します。

これは実際にはヒープの末尾に新しいノードを追加することで行われます。

さて、ヒープ特性を維持するために、最後のノードから上にトラバースし(必要に応じてスワップし)、違反している可能性のあるヒープ特性を修正します。

heappopと同様に、サブツリーの高さをトラバースするだけなので、ここでの時間複雑性はO(log n)です。

5. extractMin関数

この関数はヒープから最も優先度の高いもの(ルート要素)を返す。

ルートの値を返すだけでヒープに変更を加えず、ルートには O(1) 時間でアクセスできるので、この関数の時間複雑度は O(1) となります。

Min Heap データ構造の完全な Python 実装

以下は、PythonでMin Heapを実装するための完全なプログラムです。

Parent Node is 4 Left Child is 7 Right Child is 9
Parent Node is 7 Left Child is 15 Right Child is 13

出力。

Min Heap Python Python Content1
Min Heap Example

コクルージョン

この記事では、min heapについて学びました。

heapifyheappushheappop`の関数がどのように動作するのかを勉強した。

さらに、pythonでゼロからmin heapのデータ構造を実装しました。

今後も有益な記事を期待しています。

タイトルとURLをコピーしました