-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathbst.go
269 lines (230 loc) · 6.73 KB
/
bst.go
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
package searching
import "github.com/youngzhu/algs4-go/fund"
// We examine a symbol-table implementation that combines the flexibility of
// insertion in linked lists with the efficiency of search in an ordered array.
// Specifically, using two links per node leads to an efficient symbol-table
// implementation based on the binary search tree data structure, which qualifies
// as one of the most fundamental algorithms in computer science.
// Binary Search Tree (BST)
// BST is a binary tree where each node has a Comparable key (and an associated value)
// and satisfies the restriction that the key in any node is larger than the keys
// in all nodes in that node's left subtree and smaller than the keys in all nodes
// in that node's right subtree.
// BST implements the ordered symbol-table API using a binary search tree. We
// define a type to define nodes in BST. Each node contains a key, a value,
// a left link, a right link, and a node count. The left link points to a BST
// for items with smaller keys, and the right link points to a BST for items with
// larger keys. The variable N (size) gives the node count in the subtree rooted
// at the node. This field facilitates the implementation of various ordered
// symbol-table operations, as you will see.
// Search.
// A recursive algorithm to search for a key in a BST follows immediately from the
// recursive structure: If the tree is empty, we have a search miss; if the search
// key is equal to the key at the root, we have a search hit. Otherwise, we search
// (recursively) in the appropriate subtree. The recursive get() method implements
// this algorithm directly. It takes a node (root of a subtree) as head argument
// and a key as second argument, starting with the root of the tree and the search key.
// Insert.
// Insert is not much more difficult to implement than search. Indeed, a search for
// a key not in the tree ends a null link, and all that we need to do is replace that
// link with a new node containing the key. The recursive put() method accomplishes
// this task using logic similar to that we used for recursive search: If the tree is
// empty, we return a new node containing the key and value; if the search key is less
// than the key at the root, we set the left link to the result of inserting the key
// into the left subtree; otherwise, we set the right link to the result of inserting
// the key into the right subtree.
type BST struct {
root *treeNode // root of BST
}
type treeNode struct {
key OSTKey // sorted by key
value STValue // associated data
left, right *treeNode // left and right subtrees
size int // number of nodes in subtree
}
func NewBST() *BST {
return &BST{}
}
func newTreeNode(key OSTKey, value STValue) *treeNode {
return &treeNode{key: key, value: value, size: 1}
}
// Get returns the value associated with the given key
func (b *BST) Get(key OSTKey) STValue {
return get(b.root, key)
}
func get(x *treeNode, key OSTKey) STValue {
if key == nil {
panic("calls get() with a nil key")
}
if x == nil {
return nil
}
cmp := key.CompareTo(x.key)
if cmp < 0 {
return get(x.left, key)
} else if cmp > 0 {
return get(x.right, key)
} else {
return x.value
}
}
// Put Inserts the specified key-value pair into the symbol table, overwriting the
// old value with the new value if the symbol table already contains the specified key.
//
// Deletes the specified key (and its associated value) from the symbol table if
// the specified value is nil
func (b *BST) Put(key OSTKey, value STValue) {
if key == nil {
panic("calls put() with a nil key")
}
if value == nil {
b.Delete(key)
return
}
b.root = put(b.root, key, value)
}
func put(x *treeNode, key OSTKey, value STValue) *treeNode {
if x == nil {
return newTreeNode(key, value)
}
cmp := key.CompareTo(x.key)
if cmp < 0 {
x.left = put(x.left, key, value)
} else if cmp > 0 {
x.right = put(x.right, key, value)
} else {
x.value = value
}
x.size = 1 + size(x.left) + size(x.right)
return x
}
// return number of key-value pairs in BST rooted at x
func size(x *treeNode) int {
if x == nil {
return 0
} else {
return x.size
}
}
// Delete removes the specified key and its associated value from the symbol table
// (if the key is in this symbol table)
func (b *BST) Delete(key OSTKey) {
if key == nil {
panic("calls Delete() with a nil key")
}
b.root = delete(b.root, key)
}
func delete(x *treeNode, key OSTKey) *treeNode {
if x == nil {
return nil
}
cmp := key.CompareTo(x.key)
if cmp < 0 {
x.left = delete(x.left, key)
} else if cmp > 0 {
x.right = delete(x.right, key)
} else {
if x.left == nil {
return x.right
}
if x.right == nil {
return x.left
}
t := x
x = min(t.right)
x.right = deleteMin(t.right)
x.left = t.left
}
x.size = 1 + size(x.left) + size(x.right)
return x
}
func deleteMin(x *treeNode) *treeNode {
if x.left == nil {
return x.right
}
x.left = deleteMin(x.left)
x.size = 1 + size(x.left) + size(x.right)
return x
}
func min(x *treeNode) *treeNode {
if x.left == nil {
return x
} else {
return min(x.left)
}
}
// Keys returns all keys in the symbol table
func (b *BST) Keys() []OSTKey {
if b.IsEmpty() {
panic("The BST is empty")
}
return b.rangeKeys(b.Min(), b.Max())
}
// Returns all keys in the symbol table in the given range
func (b *BST) rangeKeys(lo, hi OSTKey) []OSTKey {
if lo == nil {
panic("head argument to rangeKeys() is nil")
}
if hi == nil {
panic("second argument to rangeKeys() is nil")
}
queue := fund.NewQueue()
keys(b.root, queue, lo, hi)
keySlice := make([]OSTKey, queue.Size())
for i, v := range queue.Iterator() {
keySlice[i] = v.(OSTKey)
}
return keySlice
}
func keys(x *treeNode, queue *fund.Queue, lo, hi OSTKey) {
if x == nil {
return
}
cmpLo := lo.CompareTo(x.key)
cmpHi := hi.CompareTo(x.key)
if cmpLo < 0 {
keys(x.left, queue, lo, hi)
}
if cmpLo <= 0 && cmpHi >= 0 {
queue.Enqueue(x.key)
}
if cmpHi > 0 {
keys(x.right, queue, lo, hi)
}
}
// Min returns the smallest key in the BST
func (b *BST) Min() OSTKey {
if b.IsEmpty() {
panic("The BST is empty")
}
return min(b.root).key
}
// Max returns the largest key in the BST
func (b *BST) Max() OSTKey {
if b.IsEmpty() {
panic("The BST is empty")
}
return max(b.root).key
}
func max(x *treeNode) *treeNode {
if x.right == nil {
return x
} else {
return max(x.right)
}
}
// IsEmpty returns true if this symbol table is empty
func (b *BST) IsEmpty() bool {
return b.Size() == 0
}
// Size returns the number of key-value pairs in this symbol table
func (b *BST) Size() int {
return size(b.root)
}
// Contains reports does this BST contains the given key?
func (b *BST) Contains(key OSTKey) bool {
if key == nil {
panic("argument to Contains() is nil")
}
return b.Get(key) != nil
}