Heap 은 완전 이진 트리에 있는 노드 중 키 값이 가장 큰 노드나 키 값이 가장 작은 노드를 찾기 위해 만들어진 자료구조이다.

Heap 은 Max Heap 과 Min Heap 이 있다.(Max Min Heap 도 있지만 생략)
Max Heap 은 부모 노드의 키값 >= 자식 노드의 키값 이면서 완전 이진 트리를 만족해야 한다.
반면 Min Heap 은 부모 노드의 키값 <= 자식 노드의 키값이면서 완전 이진 트리를 만족해야 한다.

삽입과 삭제 시에 마지막 노드가 증가, 삭제되고 노드들을 서로 교체해줘야 하며, 완전 이진 트리이므로(루트부터 마지막 노드까지는 노드가 무조건 존재) Heap 은 배열로 구현하는 게 편하다.

참고로 이진 트리를 배열로 구현하였을 때 노드의 배열 인덱스 구하는 방법은 아래와 같다.

노드의 인덱스를 i, 마지막 노드의 인덱스를 n 이라 할 때,
i의 부모 노드 i / 2(소수점 버림) 단, i > 1
i의 왼쪽 자식 노드
2 * i
단, (2 * i) <= n
i의 오른쪽 자식 노드
2 * i + 1
단, (2 * i + 1) <= n
루트 노드
1
단, 0 < n

삽입은 마지막 노드의 다음 자리에 새로운 노드를 삽입하고, 부모 노드와 비교하여 조건에 맞게 교체하는 작업을 루트 노드까지 반복한다.

삭제는 루트 노드를 삭제하고 그 자리에 마지막 노드를 올린다. 이후 부모, 왼쪽 자식, 오른쪽 자식 노드를 비교하여 힙 조건을 만족하도록 부모를 변경해 준다. 그 다음 변경된 자식 노드를 부모로 하여 이를 자식 노드가 없을때까지 반복한다.


# Heap Implementation
# Jungtaek Lim(Heart), 2009-03-04

class HeapNode
  attr_accessor :key, :value

end

class Heap

  def initialize(is_max_heap)
    @is_max_heap = is_max_heap

    @memory = []
    @last_index = 0
  end

  def insert_data(key, value)
    node = HeapNode.new
    node.key = key
    node.value = value

    @last_index += 1

    @memory[@last_index] = node

    @current_index = @last_index
    @parent_index = @current_index / 2

    while @parent_index != 0
      if true == check_swap_by_index(@parent_index, @current_index)
        swap_node(@parent_index, @current_index)
      end
      

      @current_index = @parent_index
      @parent_index = @current_index / 2
    end
    
  end

  def delete_data
    return nil if @last_index == 0

    ret_node = @memory[1]

    last_node = @memory[@last_index]

    @memory[1] = last_node
    @last_index -= 1

    current_index = 1

    while current_index < @last_index
      left_child_index = current_index * 2
      right_child_index = current_index * 2 + 1

      parent_key = @memory[current_index].key

      if left_child_index  > @last_index
        left_key = (true == @is_max_heap ? -9999999 : 9999999)
      else
        left_key = @memory[left_child_index].key
      end

      if right_child_index > @last_index
        right_key = (true == @is_max_heap ? -9999999 : 9999999)
      else
        right_key = @memory[right_child_index].key
      end
      
      if true == check_max_or_min(left_key, parent_key) &&
          true == check_max_or_min(left_key, right_key)
        swap_node(left_child_index, current_index)

        current_index = left_child_index
      elsif true == check_max_or_min(right_key, parent_key) &&
          true == check_max_or_min(right_key, left_key)
        swap_node(right_child_index, current_index)

        current_index = right_child_index
      else
        break
      end

    end

    return ret_node
  end

  def print_data
    print "["

    (1..@last_index).each do |i|
      print "(" + @memory[i].key.to_s + "," + @memory[i].value.to_s + ")"
    end

    puts "]"
  end

  private

  def check_max_or_min(key1, key2)
    if @is_max_heap
      return (key1 >= key2 ? true : false)
    else
      return (key1 <= key2 ? true : false)
    end
  end

  def check_swap_by_index(parent_index, current_index)
    if @is_max_heap
      return (@memory[@parent_index].key <= @memory[@current_index].key ? true : false)
    else
      return (@memory[@parent_index].key >= @memory[@current_index].key ? true : false)
    end
  end

  def swap_node(index1, index2)
    temp = @memory[index1]
    @memory[index1] = @memory[index2]
    @memory[index2] = temp
  end

end

def make_example_max_heap
  heap = Heap.new(true)
  
  heap.insert_data(8, 0)
  heap.insert_data(13, 0)
  heap.insert_data(10, 0)
  heap.insert_data(15, 0)
  heap.insert_data(19, 0)
  heap.insert_data(20, 0)

  return heap
end

heap = make_example_max_heap
heap.insert_data(17, 0)
heap.print_data

heap = make_example_max_heap
heap.insert_data(23, 0)
heap.print_data

heap = make_example_max_heap
heap.insert_data(14, 0)
heap.print_data
heap.delete_data
heap.print_data


결과>
[(20,0)(15,0)(19,0)(8,0)(13,0)(10,0)(17,0)]
[(23,0)(15,0)(20,0)(8,0)(13,0)(10,0)(19,0)]
[(20,0)(15,0)(19,0)(8,0)(13,0)(10,0)(14,0)]
[(19,0)(15,0)(14,0)(8,0)(13,0)(10,0)]


크리에이티브 커먼즈 라이선스
Creative Commons License

'Dev.Programming > DS/Algorithm' 카테고리의 다른 글

인접 리스트로 구현한 Graph - in Ruby  (2) 2009/03/16
인접 행렬로 구현한 Graph - in Ruby  (0) 2009/03/16
Heap - in Ruby  (0) 2009/03/05
Binary Search Tree - in Ruby  (0) 2009/03/04
Binary Tree - in Ruby  (0) 2009/03/04
Deck(Deque, Double-ended Queue) - in Ruby  (0) 2009/03/04
Posted by Heart