diff --git a/sorting/counting_sort.rb b/sorting/counting_sort.rb new file mode 100644 index 0000000..a50f636 --- /dev/null +++ b/sorting/counting_sort.rb @@ -0,0 +1,26 @@ +## +# Given a non-negative integer value_upper_bound and an array of integers arr with values between 0 and value_upper_bound, +# returns a sorted copy of the input array. +# When value_upper_bound = O(arr.length), sorting runs in O(arr.length). + +def counting_sort(arr, value_upper_bound) + if !value_upper_bound.integer? || value_upper_bound < 0 + raise ArgumentError.new("counting_sort must be invoked with integer value_upper_bound >= 0") + end + if !arr.all? { |elem| elem.integer? && elem.between?(0, value_upper_bound) } + raise ArgumentError.new("counting_sort must be invoked with integer array elements in (0..value_upper_bound)") + end + sorted_arr = Array.new(arr.length) { 0 } + tmp_arr = Array.new(value_upper_bound+1) { 0 } + for elem in arr + tmp_arr[elem] += 1 + end + for i in 1..value_upper_bound + tmp_arr[i] += tmp_arr[i-1] + end + arr.reverse_each do |elem| + sorted_arr[tmp_arr[elem]-1] = elem + tmp_arr[elem] -= 1 + end + sorted_arr +end diff --git a/sorting/counting_sort_test.rb b/sorting/counting_sort_test.rb new file mode 100644 index 0000000..8cabfba --- /dev/null +++ b/sorting/counting_sort_test.rb @@ -0,0 +1,42 @@ +require 'minitest/autorun' +require_relative 'counting_sort' + +class TestCountingSort < Minitest::Test + def test_empty_array_given_empty_array + assert counting_sort([], 1).empty? + end + + def test_array_sorted_correctly + assert counting_sort([1, 5, 3, 0, 4, 2, 4], 5) == [0, 1, 2, 3, 4, 4, 5] + end + + def test_exception_given_non_integer_upper_bound + assert_raises ArgumentError do + counting_sort([1, 3, 2], 5.5) + end + end + + def test_exception_given_negative_upper_bound + assert_raises ArgumentError do + counting_sort([1, 3, 2], -1) + end + end + + def test_exception_given_non_integer_elements + assert_raises ArgumentError do + counting_sort([1, 3, 2.5], 5) + end + end + + def test_exception_given_negative_elements + assert_raises ArgumentError do + counting_sort([1, 3, -2], 5) + end + end + + def test_exception_given_elements_above_upper_bound + assert_raises ArgumentError do + counting_sort([1, 3, 6], 5) + end + end +end