Skip to content

Commit

Permalink
Edit README; Add specs for traversal orders and yielding to a block
Browse files Browse the repository at this point in the history
  • Loading branch information
ianmandap committed Jan 10, 2025
1 parent 1ff45ab commit a21ab5e
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 55 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
My portfolio of completed projects from [The Odin Project](https://www.theodinproject.com/)

#### Ruby Projects:
* [Linked Lists](https://github.com/theIanMilan/odin-projects/tree/main/Ruby%20Linked%20Lists)
* [Binary Search Trees](https://github.com/theIanMilan/odin-projects/tree/main/Ruby%20Binary%20Search%20Trees)
* [Linked Lists](https://github.com/theIanMilan/odin-projects/tree/main/Ruby%20Linked%20Lists)

#### HTML pages live preview:
* https://theianmilan.github.io/odin-projects/Google%20Homepage/index.html
Expand Down
14 changes: 12 additions & 2 deletions Ruby Binary Search Trees/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
## Learnings
- Balanced Binary Search Trees (BST)
Here, I implemented a `Tree` class in Ruby following the Assignment metric using Test Driven Development (RSpecs).

- (Capturing multi-line console output in Ruby's RSpec testing interface)[https://blog.petefowler.dev/capturing-multi-line-console-output-in-rubys-rspec-testing-interface]
**Balanced Binary Search Trees (BST)**
- a binary tree in which height of left and right subtree of any node differ by not more than 1
- performance-wise good as they provide `O log(n)` time for search, insert and delete
- created from a sorted array

**[Capturing multi-line console output in Ruby's RSpec testing interface](https://blog.petefowler.dev/capturing-multi-line-console-output-in-rubys-rspec-testing-interface)**
- `Tree#pretty_print` outputs a tree structure to the console. To streamline RSpec testing, we assign `$stdout` to a `StringIO` object so any output is captured. We can then use `$stdout.rewind` and sequentially use `$stdout.gets` to check line by line against expected output.
- since reassigning `$stdout = StringIO` pollutes the global namespace, an `after(:each) { $stdout = STDOUT }` was put to restore test defaults. This allows the normal use of `byebug` and `puts` operations without their print execution going into `StringIO`.

**Blocks and `yield`**
- Implementation requirements for `#level_order`, `#preorder`, `#inorder`, and `#postorder` methods required for the traversed nodes to be yielded to a block, if provided, and to return an array of values if not provided.
- In method definitions, if put as the last argument, I learned the keyword `&` explicitly captures blocks and can then be yielded onto inside the method body. This allows for more flexible and powerful use as exemplified by the `#balanced?` method

```
### Assignment
Expand Down
File renamed without changes
138 changes: 87 additions & 51 deletions Ruby Binary Search Trees/spec/tree_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,99 +100,135 @@ def setup_pretty_print(tree)
expect(out.gets).to eq(" └── 2\n")
expect(out.gets).to eq(" └── 1\n")
end
end

describe '#level_order' do
context 'with a block provided' do
it 'yields each node to the block' do
nodes_arr = tree1.level_order
expect { |b| tree1.level_order(&b) }.to yield_successive_args(*nodes_arr)
end
end

describe '#level_order' do
context 'with no block provided' do
it 'returns array of nodes in level order of BST' do
expect(tree1.level_order(tree1.root).map(&:data)).to eql([2, 1, 3, 4])
expect(tree2.level_order(tree2.root).map(&:data)).to eql([4, 2, 6, 1, 3, 5, 7])
end
end
end

describe '#preorder' do
context 'with a block provided' do
it 'yields each node to the block' do
nodes_arr = tree1.preorder
expect { |b| tree1.preorder(&b) }.to yield_successive_args(*nodes_arr)
end
end

describe '#preorder' do
context 'with no block provided' do
it 'returns array of nodes in preorder of BST' do
expect(tree1.preorder(tree1.root).map(&:data)).to eql([2, 1, 3, 4])
expect(tree2.preorder(tree2.root).map(&:data)).to eql([4, 2, 1, 3, 6, 5, 7])
end
end
end

describe '#inorder' do
context 'with a block provided' do
it 'yields each node to the block' do
nodes_arr = tree1.inorder
expect { |b| tree1.inorder(&b) }.to yield_successive_args(*nodes_arr)
end
end

describe '#inorder' do
context 'with no block provided' do
it 'returns array of nodes in inorder of BST' do
expect(tree1.inorder(tree1.root).map(&:data)).to eql(array1)
expect(tree2.inorder(tree2.root).map(&:data)).to eql(array2)
end
end
end

describe '#postorder' do
context 'with a block provided' do
it 'yields each node to the block' do
nodes_arr = tree1.postorder
expect { |b| tree1.postorder(&b) }.to yield_successive_args(*nodes_arr)
end
end

describe '#postorder' do
context 'with no block provided' do
it 'returns array of nodes in postorder of BST' do
expect(tree1.postorder(tree1.root).map(&:data)).to eql([1, 4, 3, 2])
expect(tree2.postorder(tree2.root).map(&:data)).to eql([1, 3, 2, 5, 7, 6, 4])
end
end
end

describe '#find' do
it 'returns node with given value' do
expect(tree2.find(2)).to eq(tree2.root.left)
expect(tree2.find(7)).to eq(tree2.root.right.right)
expect(tree2.find(100)).to eq(nil)
end
describe '#find' do
it 'returns node with given value' do
expect(tree2.find(2)).to eq(tree2.root.left)
expect(tree2.find(7)).to eq(tree2.root.right.right)
expect(tree2.find(100)).to eq(nil)
end
end

describe '#depth' do
it 'returns depth of given node' do
tree2.insert(4.5)
describe '#depth' do
it 'returns depth of given node' do
tree2.insert(4.5)

node2 = tree2.find(2)
expect(tree2.depth(node2)).to eq(1)
node2 = tree2.find(2)
expect(tree2.depth(node2)).to eq(1)

node1 = tree2.find(4.5)
expect(tree2.depth(node1)).to eq(3)
end
node1 = tree2.find(4.5)
expect(tree2.depth(node1)).to eq(3)
end
end

describe '#height' do
it 'returns height of given node' do
tree2.insert(4.5)
describe '#height' do
it 'returns height of given node' do
tree2.insert(4.5)

node2 = tree2.find(4)
expect(tree2.height(node2)).to eq(3)
node2 = tree2.find(4)
expect(tree2.height(node2)).to eq(3)

node2 = tree2.find(2)
expect(tree2.height(node2)).to eq(1)
node2 = tree2.find(2)
expect(tree2.height(node2)).to eq(1)

node1 = tree2.find(4.5)
expect(tree2.height(node1)).to eq(0)
end
node1 = tree2.find(4.5)
expect(tree2.height(node1)).to eq(0)
end
end

describe '#balanced?' do
it 'returns true if tree is balanced' do
expect(tree1.balanced?).to eq(true)
end
describe '#balanced?' do
it 'returns true if tree is balanced' do
expect(tree1.balanced?).to eq(true)
end

it 'returns false if tree is unbalanced' do
tree1.insert(2.22)
tree1.insert(2.33)
it 'returns false if tree is unbalanced' do
tree1.insert(2.22)
tree1.insert(2.33)

expect(tree1.balanced?).to eq(false)
end
expect(tree1.balanced?).to eq(false)
end
end

describe '#rebalance' do
it 'does nothing if already balanced' do
tree_before = tree1
tree1.rebalance
expect(tree_before).to eq(tree1)
end
describe '#rebalance' do
it 'does nothing if already balanced' do
tree_before = tree1
tree1.rebalance
expect(tree_before).to eq(tree1)
end

it 'rebuilds nodes of an unbalanced tree' do
tree1.insert(2.22)
tree1.insert(2.33)
expect(tree1.balanced?).to eq(false)
it 'rebuilds nodes of an unbalanced tree' do
tree1.insert(2.22)
tree1.insert(2.33)
expect(tree1.balanced?).to eq(false)

tree1.rebalance
expect(tree1.balanced?).to eq(true)
expect(tree1.inorder.size).to eq(6)
end
tree1.rebalance
expect(tree1.balanced?).to eq(true)
expect(tree1.inorder.size).to eq(6)
end
end
end
2 changes: 1 addition & 1 deletion Ruby Linked Lists/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
## Learnings
Ruby does not have this data structure supported. Here, I implemented a `LinkedList` class in Ruby following the Assignment metric.
Ruby does not have this data structure supported. Here, I implemented a `LinkedList` class in Ruby following the Assignment metric using Test Driven Development (RSpecs)

**Linked Lists**
- are linear collections of data elements called nodes that "point" to the next node by means of a pointer
Expand Down

0 comments on commit a21ab5e

Please sign in to comment.