-
Notifications
You must be signed in to change notification settings - Fork 21
/
min_heap.rb
101 lines (86 loc) · 3.18 KB
/
min_heap.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
class MinHeap
attr_accessor :nodes
def initialize
@nodes = []
end
# Peek the minimum element
def min
@nodes.first
end
# Remove and return the root
def extract_min
@nodes.shift.tap do
# Move the last node to the root position and then heapify down
@nodes.unshift @nodes.pop unless @nodes.size.zero?
heapify_down
end
end
# Add a node to the bottom of the tree and heapify it up into position
def insert(data)
@nodes << data
heapify_up
end
private
# The children of node n are: 2n + 1 and 2n + 2
def left_child_node(index)
index * 2 + 1
end
# The children of node n are: 2n + 1 and 2n + 2
def right_child_node(index)
index * 2 + 2
end
# The parent of node n is: ceil(n / 2) - 1
def parent(index)
(index.to_f / 2).ceil - 1
end
# After adding a node to the bottom of the tree, heapify it up into position
def heapify_up
# Swap the current_node (starting with last child) with it's parent if it is smaller
previous_current_node = nil
current_node = @nodes.size - 1
# When the current_node is not changing, then it has swapped as many times as it can
until previous_current_node == current_node
previous_current_node = current_node
parent_node = parent(current_node)
# Bounds check for when the current_node is the root
break if current_node.zero?
# Swap with the parent if the parent is bigger
if @nodes[current_node] < @nodes[parent_node]
@nodes[current_node], @nodes[parent_node] = @nodes[parent_node], @nodes[current_node]
current_node = parent_node
end
end
end
# After extracting the root from the tree, heapify down the node at the root position
def heapify_down
# Swap the current_node (starting with root) with its smallest child until it's smaller than both of its children
previous_current_node = nil
current_node = 0
# When the current_node is not changing, then it has swapped as many times as it can
until previous_current_node == current_node
previous_current_node = current_node
right_child = right_child_node current_node
left_child = left_child_node current_node
# Bounds check for when current_node is one of the last two nodes
# Or if there are only two nodes total
if right_child >= @nodes.size
# Correctly order nodes if there are only two nodes
if @nodes.size == 2 && @nodes[left_child] < @nodes[current_node]
@nodes[current_node], @nodes[left_child] = @nodes[left_child], @nodes[current_node]
end
break
end
# If current_node is greater than either of its children
if @nodes[current_node] > @nodes[left_child] || @nodes[current_node] > @nodes[right_child]
# Swap with the smallest child
if @nodes[left_child] <= @nodes[right_child]
@nodes[current_node], @nodes[left_child] = @nodes[left_child], @nodes[current_node]
current_node = left_child
else
@nodes[current_node], @nodes[right_child] = @nodes[right_child], @nodes[current_node]
current_node = right_child
end
end
end
end
end