From 7fa7c5bae06440a8544afceb5e2ee8b363906f3d Mon Sep 17 00:00:00 2001 From: Amos Paribocci Date: Mon, 6 Feb 2023 18:45:44 +0100 Subject: [PATCH 1/2] Adding max-heap implementation --- data_structures/heaps/max_heap.rb | 87 ++++++++++++++++++++++++++ data_structures/heaps/max_heap_test.rb | 36 +++++++++++ 2 files changed, 123 insertions(+) create mode 100644 data_structures/heaps/max_heap.rb create mode 100644 data_structures/heaps/max_heap_test.rb diff --git a/data_structures/heaps/max_heap.rb b/data_structures/heaps/max_heap.rb new file mode 100644 index 0000000..7996f7c --- /dev/null +++ b/data_structures/heaps/max_heap.rb @@ -0,0 +1,87 @@ +## +# This class represents an array-backed max-heap. + +class MaxHeap + + attr_reader :arr + attr_accessor :heap_size + + ## + # Creates a new max-heap using the provided collection of initial values, if provided (empty by default). + # Note: a clone of the input collection is created to avoid alterations to the input. + + def initialize(elements = []) + @arr = [0] + elements.map(&:clone) + @heap_size = arr.size - 1 + for i in ((arr.size / 2).floor).downto 1 + max_heapify(i) + end + end + + def to_array + return arr[1..heap_size].map(&:clone) + end + + def empty? + return heap_size == 0 + end + + def max + return nil if empty? + return @arr[1] + end + + def extract_max + return nil if empty? + m = max + @arr[1] = @arr[heap_size] + @heap_size -= 1 + max_heapify(1) + return m + end + + def insert(k) + @heap_size += 1 + @arr[heap_size] = -Float::INFINITY + increase_to(heap_size, k) + end + + private + def max_heapify(i) + l = left(i) + r = right(i) + m = i + if l <= heap_size && arr[l] > arr[i] + m = l + end + if r <= heap_size && arr[r] > arr[m] + m = r + end + if m != i + arr[i], arr[m] = arr[m], arr[i] + max_heapify(m) + end + end + + def increase_to(i, k) + raise ArgumentError.new('MaxHeap#increase_to does not support lower values for the key') if arr[i] > k + @arr[i] = k + j = i + while parent(j) > 0 && arr[parent(j)] < arr[j] + arr[j], arr[parent(j)] = arr[parent(j)], arr[j] + j = parent(j) + end + end + + def parent(i) + return (i / 2).floor + end + + def left(i) + return 2*i + end + + def right(i) + return 2*i + 1 + end +end \ No newline at end of file diff --git a/data_structures/heaps/max_heap_test.rb b/data_structures/heaps/max_heap_test.rb new file mode 100644 index 0000000..502fe6f --- /dev/null +++ b/data_structures/heaps/max_heap_test.rb @@ -0,0 +1,36 @@ +require 'minitest/autorun' +require_relative 'max_heap' + +class TestMaxHeap < Minitest::Test + def test_to_array_returns_array_representation + heap = MaxHeap.new([4, 1, 3, 3, 16, 9, 10, 14, 8, 7]) + assert heap.to_array == [16, 14, 10, 8, 7, 9, 3, 3, 4, 1] + end + + def test_empty_returns_true_for_empty_heap + heap = MaxHeap.new + assert heap.empty? + end + + def test_empty_returns_false_for_non_empty_heap + heap = MaxHeap.new([1]) + assert !heap.empty? + end + + def test_max_returns_maximum_heap_element + heap = MaxHeap.new([4, 1, 3]) + assert heap.max == 4 + end + + def test_extract_max_returns_and_removes_maximum_heap_element + heap = MaxHeap.new([4, 1, 3]) + assert heap.extract_max == 4 + assert heap.to_array == [3, 1] + end + + def test_insert_adds_element_to_appropriate_position + heap = MaxHeap.new([4, 1, 3]) + heap.insert(2) + assert heap.to_array == [4, 2, 3, 1] + end +end From fb1f5dd67936be0919f25578b27fc8b246585f68 Mon Sep 17 00:00:00 2001 From: Amos Paribocci Date: Mon, 6 Feb 2023 18:52:42 +0100 Subject: [PATCH 2/2] Adding unit tests for element not found in max-heap --- data_structures/heaps/max_heap_test.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/data_structures/heaps/max_heap_test.rb b/data_structures/heaps/max_heap_test.rb index 502fe6f..ef0bbf7 100644 --- a/data_structures/heaps/max_heap_test.rb +++ b/data_structures/heaps/max_heap_test.rb @@ -22,12 +22,22 @@ class TestMaxHeap < Minitest::Test assert heap.max == 4 end + def test_max_returns_nil_if_empty_heap + heap = MaxHeap.new + assert heap.max.nil? + end + def test_extract_max_returns_and_removes_maximum_heap_element heap = MaxHeap.new([4, 1, 3]) assert heap.extract_max == 4 assert heap.to_array == [3, 1] end + def test_extract_max_returns_nil_if_empty_heap + heap = MaxHeap.new + assert heap.extract_max.nil? + end + def test_insert_adds_element_to_appropriate_position heap = MaxHeap.new([4, 1, 3]) heap.insert(2)