実際に疑似コードを Ruby で実装
Ruby の配列への[]のアクセスは、アルゴリズムイントロダクションの擬似コードの配列 -1 なので、 アルゴリズムイントロダクションと同じ挙動をする HArray を定義する
class HArray < DelegateClass(Array)
attr_accessor :heap_size
def initialize(a = [])
super(a)
self.heap_size = a.length
end
def [](key)
__getobj__[key-1]
end
def []=(key, val)
__getobj__[key-1]= val
end
end
# Array[0] == HArray[1]
def parent(i) i / 2 end def left(i) 2 * i end def right(i) 2 * i + 1 end
maxヒープの実装
まずは max_heapify.
指定した添え字と子が、max-heap な構造になるように滑り落とす
def max_heapify(a, i)
l = left(i)
r = right(i)
if l <= a.heap_size && a[l] > a[i]
then largest = l
else largest = i ;end
if r <= a.heap_size && a[r] > a[largest]
then largest = r ;end
if largest != i
then a[i], a[largest] = a[largest], a[i]
max_heapify(a, largest) ;end; end
# P125 a = HArray.new([16,4,10,14,7,9,3,2,8,1]) max_heapify(a, 2) p a
ボトムアップで max_heapify を利用することで、max ヒープを構築することができるよ
def build_max_heap(a)
a.heap_size = a.length
for i in (a.length/2).downto 1
max_heapify(a, i) ;end ;end
# P127 a = HArray.new([4,1,3,2,16,9,10,14,8,7]) build_max_heap(a) p a
P128 で、build_max_heap のコストは O(n) なので、未ソートのときからmax_heap を線形時間で構成可能だよ
def heap_sort(a)
build_max_heap(a)
a.heap_size = a.length
for i in a.length.downto 2
a[1], a[i] = a[i], a[1]
a.heap_size = a.heap_size - 1
max_heapify(a, 1) ;end ;end
# P130 a = HArray.new([4,1,3,2,16,9,10,14,8,7]) heap_sort(a) p a
キーの値を大きい値に変更し、max_heap を構築
def heap_increse_key(a, i, key)
if key < a[i]
then raise '新しいは現在のキーより小さい' ;end
a[i] = key
while i > 1 && a[parent(i)] < a[i]
a[i], a[parent(i)] = a[parent(i)], a[i]
i = parent(i) ;end ;end
ヒープを一つ増やし、max_heap を構築
def max_heap_insert(a, key) a.heap_size = a.heap_size + 1 a[a.heap_size] = -Float::MAX heap_increse_key(a, a.heap_size, key); end