Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit e6ae910

Browse files
authored
Merge pull request #334 from itsmegrave/main
✨ Add ruby BST
2 parents 9b7e6d2 + 2227ce5 commit e6ae910

File tree

2 files changed

+217
-2
lines changed

2 files changed

+217
-2
lines changed

‎README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,8 +1776,8 @@ In order to achieve greater coverage and encourage more people to contribute to
17761776
</a>
17771777
</td>
17781778
<td> <!-- Ruby -->
1779-
<a href="./CONTRIBUTING.md">
1780-
<img align="center" height="25" src="./logos/github.svg" />
1779+
<a href="./src/ruby/binary_search_tree.rb">
1780+
<img align="center" height="25" src="./logos/ruby.svg" />
17811781
</a>
17821782
</td>
17831783
<td> <!-- JavaScript -->

‎src/ruby/binary_search_tree.rb‎

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
# frozen_string_literal: true
2+
3+
class BinarySearchTree
4+
class Node
5+
attr_accessor :left, :right, :value
6+
7+
def initialize(value)
8+
@left = nil
9+
@right = nil
10+
@value = value
11+
end
12+
end
13+
14+
def initialize
15+
@root = nil
16+
end
17+
18+
attr_reader :root
19+
20+
def insert(value)
21+
new_node = Node.new(value)
22+
23+
if @root.nil?
24+
@root = new_node
25+
return self
26+
end
27+
28+
current_node = @root
29+
30+
loop do
31+
if value < current_node.value
32+
if current_node.left.nil?
33+
current_node.left = new_node
34+
return self
35+
end
36+
current_node = current_node.left
37+
else
38+
if current_node.right.nil?
39+
current_node.right = new_node
40+
return self
41+
end
42+
current_node = current_node.right
43+
end
44+
end
45+
46+
self
47+
end
48+
49+
def lookup(value)
50+
return nil if @root.nil?
51+
52+
current_node = @root
53+
54+
until current_node.nil?
55+
if value < current_node.value
56+
current_node = current_node.left
57+
elsif value > current_node.value
58+
current_node = current_node.right
59+
else
60+
return current_node
61+
end
62+
end
63+
64+
nil
65+
end
66+
67+
def remove(value)
68+
return false if @root.nil?
69+
70+
current_node = @root
71+
parent_node = nil
72+
73+
while current_node
74+
if value < current_node.value
75+
parent_node = current_node
76+
current_node = current_node.left
77+
elsif value > current_node.value
78+
parent_node = current_node
79+
current_node = current_node.right
80+
elsif current_node.value == value
81+
# We have a match, get to work!
82+
83+
if current_node.right.nil?
84+
update_parent_link(parent_node, current_node, current_node.left)
85+
elsif current_node.right.left.nil?
86+
current_node.right.left = current_node.left
87+
update_parent_link(parent_node, current_node, current_node.right)
88+
else
89+
leftmost, leftmost_parent = find_leftmost(current_node.right)
90+
leftmost_parent.left = leftmost.right
91+
leftmost.left = current_node.left
92+
leftmost.right = current_node.right
93+
update_parent_link(parent_node, current_node, leftmost)
94+
end
95+
96+
return true
97+
end
98+
end
99+
100+
false
101+
end
102+
103+
def traverse(node = @root)
104+
return nil if node.nil?
105+
106+
tree = { value: node.value }
107+
tree[:left] = traverse(node.left)
108+
tree[:right] = traverse(node.right)
109+
110+
tree
111+
end
112+
113+
private
114+
115+
def update_parent_link(parent_node, current_node, new_node)
116+
if parent_node.nil?
117+
@root = new_node
118+
elsif current_node.value < parent_node.value
119+
parent_node.left = new_node
120+
else
121+
parent_node.right = new_node
122+
end
123+
end
124+
125+
def find_leftmost(node)
126+
leftmost = node.left
127+
leftmost_parent = node
128+
129+
while leftmost.left
130+
leftmost_parent = leftmost
131+
leftmost = leftmost.left
132+
end
133+
134+
[leftmost, leftmost_parent]
135+
end
136+
end
137+
138+
RSpec.describe BinarySearchTree do
139+
let(:bst) { BinarySearchTree.new }
140+
141+
before(:each) do
142+
# Construct the following tree:
143+
#
144+
# 9
145+
# 4 20
146+
# 1 6 15 170
147+
#
148+
bst.insert(9)
149+
bst.insert(4)
150+
bst.insert(6)
151+
bst.insert(20)
152+
bst.insert(170)
153+
bst.insert(15)
154+
bst.insert(1)
155+
end
156+
157+
describe "#insert" do
158+
it "adds a value to the tree" do
159+
expect(bst.traverse).to eq({ value: 9,
160+
left: { value: 4,
161+
left: { value: 1, left: nil, right: nil },
162+
right: { value: 6, left: nil, right: nil } },
163+
right: { value: 20, left: { value: 15, left: nil, right: nil },
164+
right: { value: 170, left: nil, right: nil } } })
165+
end
166+
end
167+
168+
describe "#lookup" do
169+
it "finds a value in the tree" do
170+
node = bst.lookup(15)
171+
expect(node.value).to eq(15)
172+
end
173+
174+
it "returns nil for a value not in the tree" do
175+
node = bst.lookup(100)
176+
expect(node).to be_nil
177+
end
178+
end
179+
180+
describe "#remove" do
181+
it "removes a leaf node" do
182+
expect(bst.remove(1)).to be true
183+
184+
expect(bst.traverse).to eq({ value: 9,
185+
left: { value: 4, left: nil,
186+
right: { value: 6, left: nil, right: nil } },
187+
right: { value: 20, left: { value: 15, left: nil, right: nil },
188+
right: { value: 170, left: nil, right: nil } } })
189+
end
190+
191+
it "removes a node with one child" do
192+
expect(bst.remove(20)).to be true
193+
194+
expect(bst.traverse).to eq({ value: 9,
195+
left: { value: 4, left: { value: 1, left: nil, right: nil },
196+
right: { value: 6, left: nil, right: nil } },
197+
right: { value: 170, left: { value: 15, left: nil, right: nil },
198+
right: nil } })
199+
end
200+
201+
it "removes a node with two children" do
202+
expect(bst.remove(4)).to be true
203+
204+
expect(bst.traverse).to eq({ value: 9,
205+
left: { value: 6, left: { value: 1, left: nil, right: nil },
206+
right: nil },
207+
right: { value: 20, left: { value: 15, left: nil, right: nil },
208+
right: { value: 170, left: nil, right: nil } } })
209+
end
210+
211+
it "returns false for a value not in the tree" do
212+
expect(bst.remove(100)).to be false
213+
end
214+
end
215+
end

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /