Skip to content

Commit 7fa7c5b

Browse files
committed
Adding max-heap implementation
1 parent 3966a34 commit 7fa7c5b

File tree

2 files changed

+123
-0
lines changed

2 files changed

+123
-0
lines changed

data_structures/heaps/max_heap.rb

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
##
2+
# This class represents an array-backed max-heap.
3+
4+
class MaxHeap
5+
6+
attr_reader :arr
7+
attr_accessor :heap_size
8+
9+
##
10+
# Creates a new max-heap using the provided collection of initial values, if provided (empty by default).
11+
# Note: a clone of the input collection is created to avoid alterations to the input.
12+
13+
def initialize(elements = [])
14+
@arr = [0] + elements.map(&:clone)
15+
@heap_size = arr.size - 1
16+
for i in ((arr.size / 2).floor).downto 1
17+
max_heapify(i)
18+
end
19+
end
20+
21+
def to_array
22+
return arr[1..heap_size].map(&:clone)
23+
end
24+
25+
def empty?
26+
return heap_size == 0
27+
end
28+
29+
def max
30+
return nil if empty?
31+
return @arr[1]
32+
end
33+
34+
def extract_max
35+
return nil if empty?
36+
m = max
37+
@arr[1] = @arr[heap_size]
38+
@heap_size -= 1
39+
max_heapify(1)
40+
return m
41+
end
42+
43+
def insert(k)
44+
@heap_size += 1
45+
@arr[heap_size] = -Float::INFINITY
46+
increase_to(heap_size, k)
47+
end
48+
49+
private
50+
def max_heapify(i)
51+
l = left(i)
52+
r = right(i)
53+
m = i
54+
if l <= heap_size && arr[l] > arr[i]
55+
m = l
56+
end
57+
if r <= heap_size && arr[r] > arr[m]
58+
m = r
59+
end
60+
if m != i
61+
arr[i], arr[m] = arr[m], arr[i]
62+
max_heapify(m)
63+
end
64+
end
65+
66+
def increase_to(i, k)
67+
raise ArgumentError.new('MaxHeap#increase_to does not support lower values for the key') if arr[i] > k
68+
@arr[i] = k
69+
j = i
70+
while parent(j) > 0 && arr[parent(j)] < arr[j]
71+
arr[j], arr[parent(j)] = arr[parent(j)], arr[j]
72+
j = parent(j)
73+
end
74+
end
75+
76+
def parent(i)
77+
return (i / 2).floor
78+
end
79+
80+
def left(i)
81+
return 2*i
82+
end
83+
84+
def right(i)
85+
return 2*i + 1
86+
end
87+
end
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
require 'minitest/autorun'
2+
require_relative 'max_heap'
3+
4+
class TestMaxHeap < Minitest::Test
5+
def test_to_array_returns_array_representation
6+
heap = MaxHeap.new([4, 1, 3, 3, 16, 9, 10, 14, 8, 7])
7+
assert heap.to_array == [16, 14, 10, 8, 7, 9, 3, 3, 4, 1]
8+
end
9+
10+
def test_empty_returns_true_for_empty_heap
11+
heap = MaxHeap.new
12+
assert heap.empty?
13+
end
14+
15+
def test_empty_returns_false_for_non_empty_heap
16+
heap = MaxHeap.new([1])
17+
assert !heap.empty?
18+
end
19+
20+
def test_max_returns_maximum_heap_element
21+
heap = MaxHeap.new([4, 1, 3])
22+
assert heap.max == 4
23+
end
24+
25+
def test_extract_max_returns_and_removes_maximum_heap_element
26+
heap = MaxHeap.new([4, 1, 3])
27+
assert heap.extract_max == 4
28+
assert heap.to_array == [3, 1]
29+
end
30+
31+
def test_insert_adds_element_to_appropriate_position
32+
heap = MaxHeap.new([4, 1, 3])
33+
heap.insert(2)
34+
assert heap.to_array == [4, 2, 3, 1]
35+
end
36+
end

0 commit comments

Comments
 (0)