ruby - binary-search-tree
This commit is contained in:
		
							
								
								
									
										84
									
								
								ruby/binary-search-tree/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								ruby/binary-search-tree/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -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. | ||||||
							
								
								
									
										30
									
								
								ruby/binary-search-tree/binary_search_tree.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								ruby/binary-search-tree/binary_search_tree.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||||
							
								
								
									
										101
									
								
								ruby/binary-search-tree/binary_search_tree_test.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								ruby/binary-search-tree/binary_search_tree_test.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||||
		Reference in New Issue
	
	Block a user