From b430f350820739c8014661073d8ea21bb484ed56 Mon Sep 17 00:00:00 2001 From: James Walker Date: Wed, 10 Oct 2018 20:24:56 -0400 Subject: [PATCH] ruby - binary-search-tree --- ruby/binary-search-tree/README.md | 84 +++++++++++++++ ruby/binary-search-tree/binary_search_tree.rb | 30 ++++++ .../binary_search_tree_test.rb | 101 ++++++++++++++++++ 3 files changed, 215 insertions(+) create mode 100644 ruby/binary-search-tree/README.md create mode 100644 ruby/binary-search-tree/binary_search_tree.rb create mode 100644 ruby/binary-search-tree/binary_search_tree_test.rb diff --git a/ruby/binary-search-tree/README.md b/ruby/binary-search-tree/README.md new file mode 100644 index 0000000..da935c2 --- /dev/null +++ b/ruby/binary-search-tree/README.md @@ -0,0 +1,84 @@ +# Binary Search Tree + +Insert and search for numbers in a binary tree. + +When we need to represent sorted data, an array does not make a good +data structure. + +Say we have the array `[1, 3, 4, 5]`, and we add 2 to it so it becomes +`[1, 3, 4, 5, 2]` now we must sort the entire array again! We can +improve on this by realizing that we only need to make space for the new +item `[1, nil, 3, 4, 5]`, and then adding the item in the space we +added. But this still requires us to shift many elements down by one. + +Binary Search Trees, however, can operate on sorted data much more +efficiently. + +A binary search tree consists of a series of connected nodes. Each node +contains a piece of data (e.g. the number 3), a variable named `left`, +and a variable named `right`. The `left` and `right` variables point at +`nil`, or other nodes. Since these other nodes in turn have other nodes +beneath them, we say that the left and right variables are pointing at +subtrees. All data in the left subtree is less than or equal to the +current node's data, and all data in the right subtree is greater than +the current node's data. + +For example, if we had a node containing the data 4, and we added the +data 2, our tree would look like this: + + 4 + / + 2 + +If we then added 6, it would look like this: + + 4 + / \ + 2 6 + +If we then added 3, it would look like this + + 4 + / \ + 2 6 + \ + 3 + +And if we then added 1, 5, and 7, it would look like this + + 4 + / \ + / \ + 2 6 + / \ / \ + 1 3 5 7 + +* * * * + +For installation and learning resources, refer to the +[exercism help page](http://exercism.io/languages/ruby). + +For running the tests provided, you will need the Minitest gem. Open a +terminal window and run the following command to install minitest: + + gem install minitest + +If you would like color output, you can `require 'minitest/pride'` in +the test file, or note the alternative instruction, below, for running +the test file. + +Run the tests from the exercise directory using the following command: + + ruby binary_search_tree_test.rb + +To include color from the command line: + + ruby -r minitest/pride binary_search_tree_test.rb + + +## Source + +Josh Cheek [https://twitter.com/josh_cheek](https://twitter.com/josh_cheek) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/ruby/binary-search-tree/binary_search_tree.rb b/ruby/binary-search-tree/binary_search_tree.rb new file mode 100644 index 0000000..77e0553 --- /dev/null +++ b/ruby/binary-search-tree/binary_search_tree.rb @@ -0,0 +1,30 @@ +# class Bst +class Bst + attr_reader :data, :left, :right + + def initialize(data) + @data = data + end + + def insert(data) + data <= @data ? insert_left(data) : insert_right(data) + end + + def each(&block) + return enum_for(:each) unless block_given? + + @left.each(&block) if left + yield data + @right.each(&block) if right + end + + private + + def insert_left(data) + @left ? @left.insert(data) : @left = self.class.new(data) + end + + def insert_right(data) + @right ? @right.insert(data) : @right = self.class.new(data) + end +end diff --git a/ruby/binary-search-tree/binary_search_tree_test.rb b/ruby/binary-search-tree/binary_search_tree_test.rb new file mode 100644 index 0000000..c6f5e70 --- /dev/null +++ b/ruby/binary-search-tree/binary_search_tree_test.rb @@ -0,0 +1,101 @@ +require 'minitest/autorun' +require_relative 'binary_search_tree' + +class BstTest < Minitest::Test + def test_data_is_retained + assert_equal 4, Bst.new(4).data + end + + def test_inserting_less + # skip + four = Bst.new 4 + four.insert 2 + assert_equal 4, four.data + assert_equal 2, four.left.data + end + + def test_inserting_same + # skip + four = Bst.new 4 + four.insert 4 + assert_equal 4, four.data + assert_equal 4, four.left.data + end + + def test_inserting_right + # skip + four = Bst.new 4 + four.insert 5 + assert_equal 4, four.data + assert_equal 5, four.right.data + end + + def test_complex_tree + # skip + four = Bst.new 4 + four.insert 2 + four.insert 6 + four.insert 1 + four.insert 3 + four.insert 7 + four.insert 5 + assert_equal 4, four.data + assert_equal 2, four.left.data + assert_equal 1, four.left.left.data + assert_equal 3, four.left.right.data + assert_equal 6, four.right.data + assert_equal 5, four.right.left.data + assert_equal 7, four.right.right.data + end + + def record_all_data(bst) + all_data = [] + bst.each { |data| all_data << data } + all_data + end + + def test_iterating_one_element + # skip + assert_equal [4], record_all_data(Bst.new(4)) + end + + def test_iterating_over_smaller_element + # skip + four = Bst.new 4 + four.insert 2 + assert_equal [2, 4], record_all_data(four) + end + + def test_iterating_over_larger_element + # skip + four = Bst.new 4 + four.insert 5 + assert_equal [4, 5], record_all_data(four) + end + + def test_iterating_over_complex_tree + # skip + four = Bst.new 4 + four.insert 2 + four.insert 1 + four.insert 3 + four.insert 6 + four.insert 7 + four.insert 5 + assert_equal [1, 2, 3, 4, 5, 6, 7], record_all_data(four) + end + + def test_each_returns_enumerator_if_no_block + # skip + + tree = Bst.new 4 + [2, 1, 3, 6, 7, 5].each { |x| tree.insert x } + each_enumerator = tree.each + + assert_kind_of Enumerator, each_enumerator + + (1..7).each { |x| assert_equal(x, each_enumerator.next) } + + assert_raises(StopIteration) { each_enumerator.next } + end +end