-
-
Notifications
You must be signed in to change notification settings - Fork 305
Expand file tree
/
Copy pathbst.rb
More file actions
176 lines (155 loc) · 4.61 KB
/
Copy pathbst.rb
File metadata and controls
176 lines (155 loc) · 4.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
class BinarySearchTreeNode
attr_reader :key
attr_accessor :left
attr_accessor :right
def initialize(key)
@key = key
end
end
##
# This class represents a binary search tree (not implementing self-balancing) with distinct node keys.
# Starting from the root, every node has up to two children (one left and one right child node).
#
# For the BST property:
# - the keys of nodes in the left subtree of a node are strictly less than the key of the node;
# - the keys of nodes in the right subtree of a node are strictly greater than the key of the node.
#
# The main operations of this data structure (insertion, deletion, membership) run - in worst case - in O(n),
# where n is the number of nodes in the tree.
# The average case for those operations is O(log(n)) due to the structure of the tree.
class BinarySearchTree
attr_reader :size
attr_accessor :root
def initialize(keys=[])
@size = 0
keys.each {|key| insert_key(key) }
end
def empty?
size == 0
end
def insert_key(key)
@size += 1
if root.nil?
@root = BinarySearchTreeNode.new(key)
return
end
parent = root
while (key < parent.key && !parent.left.nil? && parent.left.key != key) ||
(key > parent.key && !parent.right.nil? && parent.right.key != key)
parent = key < parent.key ? parent.left : parent.right
end
if key < parent.key
raise ArgumentError.new("Key #{key} is already present in the BinarySearchTree") unless parent.left.nil?
parent.left = BinarySearchTreeNode.new(key)
else
raise ArgumentError.new("Key #{key} is already present in the BinarySearchTree") unless parent.right.nil?
parent.right = BinarySearchTreeNode.new(key)
end
end
def min_key(node=root)
return nil if node.nil?
min_key_node(node).key
end
def max_key(node=root)
return nil if node.nil?
max_key_node(node).key
end
def contains_key?(key)
!find_node_with_key(key).nil?
end
def delete_key(key)
parent = find_parent_of_node_with_key(key)
if parent.nil?
return if root.nil? || root.key != key
@size -= 1
@root = adjusted_subtree_after_deletion(root.left, root.right)
return
end
if key < parent.key
node = parent.left
parent.left = adjusted_subtree_after_deletion(node.left, node.right)
else
node = parent.right
parent.right = adjusted_subtree_after_deletion(node.left, node.right)
end
@size -= 1
end
def traverse_preorder(key_consumer, node=root)
return if node.nil?
key_consumer.call(node.key)
traverse_preorder(key_consumer, node.left) unless node.left.nil?
traverse_preorder(key_consumer, node.right) unless node.right.nil?
end
def traverse_inorder(key_consumer, node=root)
return if node.nil?
traverse_inorder(key_consumer, node.left) unless node.left.nil?
key_consumer.call(node.key)
traverse_inorder(key_consumer, node.right) unless node.right.nil?
end
def traverse_postorder(key_consumer, node=root)
return if node.nil?
traverse_postorder(key_consumer, node.left) unless node.left.nil?
traverse_postorder(key_consumer, node.right) unless node.right.nil?
key_consumer.call(node.key)
end
def to_array(visit_traversal=:traverse_preorder)
visited = []
method(visit_traversal).call(->(key) { visited.append(key) })
visited
end
private
def min_key_node(node=root)
return nil if node.nil?
until node.left.nil?
node = node.left
end
node
end
def max_key_node(node=root)
return nil if node.nil?
until node.right.nil?
node = node.right
end
node
end
def find_node_with_key(key)
node = root
until node.nil? || node.key == key
node = key < node.key ? node.left : node.right
end
node
end
def find_parent_of_node_with_key(key)
return nil if root.nil? || root.key == key
parent = root
until parent.nil?
if key < parent.key
return nil if parent.left.nil?
return parent if parent.left.key == key
parent = parent.left
else
return nil if parent.right.nil?
return parent if parent.right.key == key
parent = parent.right
end
end
nil
end
def adjusted_subtree_after_deletion(left, right)
return right if left.nil?
return left if right.nil?
if right.left.nil?
right.left = left
return right
end
successor_parent = right
until successor_parent.left.left.nil?
successor_parent = successor_parent.left
end
successor = successor_parent.left
successor_parent.left = successor.right
successor.right = right
successor.left = left
successor
end
end