常に子よりも親が大きい(小さい)値の二分木をヒープという。

常に子よりも親が大きい(小さい)値の二分木をヒープという。

2分木を配列で表現すると各要素の位置関係は
n の親は n - 1 / 2
n の左の子は 2 * n + 1
n の右の子は 2 * (n + 1)
となる。

       0
       |
    +--+--+
    1     2
    |     |
  +-+-+ +-+-+
  |   | |   |
  3   4 5   6 

[0,1,2,3,4,5,6]

S式で表現すると以下になる。

(0  ;; 0 には 1 と 2 の子がある。 
   (1 
     (3 * *) 
     (4 * *)) 
   (2 
     (5 * *)
     (6 * *)))

ヒープの条件を満たしながらデータを追加していく。

def parent(n); (n - 1) / 2 end

def array_swap(array,a,b)
  array[a],array[b] = array[b],array[a]
  array
end

def array_ifswap(array,a,b)
  array[a] > array[b] ? array_swap(array,a,b) : array
end

# 親より値が大きかれば値を交換。
def change(array,pos)
  if pos.zero?
    array 
  else 
    new_p = parent(pos)
    change(array_ifswap(array, pos, new_p), new_p)
  end
end

# ヒープに値を追加。
def pushHeap(array, elem)
  change(array.push(elem), array.size-1)
end

# 二分木をS式で表示
def show_tree(array, length, n)
  "(#{array[n]} " +
  show_leaf(array, length, 2 * n + 1) +
  show_leaf(array, length, 2 * (n + 1)) +  ")"
end

def show_leaf(array, length, pos)
  pos <= length ? show_tree(array, length, pos) : "e "
end


array = []
10.times do
 p pushHeap(array, rand(100))
end

#=>
[45]
[45, 14]
[55, 14, 45]
[55, 44, 45, 14]
[55, 44, 45, 14, 24]
[55, 44, 45, 14, 24, 13]
[55, 44, 45, 14, 24, 13, 38]
[81, 55, 45, 44, 24, 13, 38, 14]
[81, 76, 45, 55, 24, 13, 38, 14, 44]
[90, 81, 45, 55, 76, 13, 38, 14, 44, 24]

puts show_tree(array, array.size, 0)
#=>
(90 (81 (55 (14 e e )(44 e e ))(76 (24 e e )( e e )))
    (45 (13 e e )(38 e e )))

90の子は81と45、81の子は55と76・・・と条件を満たしている。