-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathcursor.go
240 lines (216 loc) · 6.48 KB
/
cursor.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
package stree
import "slices"
// A Cursor is an anchor to a location within a Tree that can be used to
// navigate the structure of the tree. A cursor is Valid if it points to a
// non-empty subtree of its tree.
type Cursor[T any] struct {
// The sequence of nodes from the root to the current item.
// The pointers are shared with the underlying tree.
// If this is empty, the cursor is invalid.
path []*node[T]
}
// Valid reports whether c is a valid cursor, meaning it points to a non-empty
// subtree of its containing tree. A nil Cursor is treated as invalid.
func (c *Cursor[T]) Valid() bool { return c != nil && len(c.path) != 0 }
// Clone returns a clone of c that points to the same location, but which is
// unaffected by subsequent movement of c (and vice versa).
func (c *Cursor[T]) Clone() *Cursor[T] {
if !c.Valid() {
return c
}
return &Cursor[T]{path: slices.Clone(c.path)}
}
// Key returns the key at the current location of the cursor.
// An invalid Cursor returns a zero-valued key.
func (c *Cursor[T]) Key() T {
if c.Valid() {
return c.path[len(c.path)-1].X
}
var zero T
return zero
}
// findNext reports the location of the successor of c.
// If no successor exists, it returns (nil, -1).
//
// If the successor is a descendant of c, it returns (right, -1) where right is
// the right child of c.
//
// Otherwise the successor is an ancestor of c, and it returns (nil, i) giving
// the offset i in the path where that ancestor is located.
//
// Precondition: c is valid.
func (c *Cursor[T]) findNext() (*node[T], int) {
i := len(c.path) - 1
// If the current node has a right subtree, its successor is there.
if min := c.path[i].right; min != nil {
return min, -1
}
// Otherwise, we have to walk back up the tree. If the current node is the
// left child of its parent, the parent is its successor. If not, we keep
// going until we find an ancestor that IS the left child of its parent. If
// no such ancestor exists, there is no successor.
j := i - 1 // j is parent, i is child
for j >= 0 {
// The current node is the left child of its parent.
if c.path[i] == c.path[j].left {
return nil, j
}
i = j
j--
}
return nil, -1
}
// HasNext reports whether c has a successor.
// An invalid cursor has no successor.
func (c *Cursor[T]) HasNext() bool {
if c.Valid() {
n, i := c.findNext()
return n != nil || i >= 0
}
return false
}
// Next advances c to its successor in the tree, and returns c.
// If c had no successor, it becomes invalid.
func (c *Cursor[T]) Next() *Cursor[T] {
if c.Valid() {
min, j := c.findNext()
if min != nil {
for ; min != nil; min = min.left {
c.path = append(c.path, min)
}
} else if j >= 0 {
c.path = c.path[:j+1]
} else {
c.path = nil
}
}
return c
}
// findPrev reports the location of the predecessor of c.
// If no predecessor exists, it returns (nil, -1).
//
// If the predecessor is a descendant of c, it returns (left, -1) where left is
// the left child of c.
//
// Otherwise the predecessoris an ancestor of c, and it returns (nil, i) giving
// the offset i in the path where that ancestor is located.
//
// Precondition: c is valid.
func (c *Cursor[T]) findPrev() (*node[T], int) {
i := len(c.path) - 1
// If the current node has a left subtree, its predecessor is there.
if max := c.path[i].left; max != nil {
return max, -1
}
// Otherwise, we have to walk back up the tree. If the current node is the
// right child of its parent, the parent is its predecessor. If not, we keep
// going until we find an ancestor that IS the right child of its parent.
// If no such ancestor exists, there is no predecessor.
j := i - 1 // j is parent, i is child
for j >= 0 {
// The current node is the right child of its parent.
if c.path[i] == c.path[j].right {
return nil, j
}
i = j
j--
}
return nil, -1
}
// HasPrev reports whether c has a predecessor.
// An invalid cursor has no predecessor.
func (c *Cursor[T]) HasPrev() bool {
if c.Valid() {
n, i := c.findPrev()
return n != nil || i >= 0
}
return false
}
// Prev advances c to its predecessor in the tree, and returns c.
// If c had no predecessor, it becomes invalid.
func (c *Cursor[T]) Prev() *Cursor[T] {
if c.Valid() {
max, j := c.findPrev()
if max != nil {
for ; max != nil; max = max.right {
c.path = append(c.path, max)
}
} else if j >= 0 {
c.path = c.path[:j+1]
} else {
c.path = nil
}
}
return c
}
// HasLeft reports whether c has a non-empty left subtree.
// An invalid cursor has no left subtree.
func (c *Cursor[t]) HasLeft() bool { return c.Valid() && c.path[len(c.path)-1].left != nil }
// Left moves to the left subtree of c, and returns c.
// If c had no left subtree, it becomes invalid.
func (c *Cursor[T]) Left() *Cursor[T] {
if c.Valid() {
if left := c.path[len(c.path)-1].left; left != nil {
c.path = append(c.path, left)
} else {
c.path = nil // invalidate
}
}
return c
}
// HasRight reports whether c has a non-empty right subtree.
// An invalid cursor has no right subtree.
func (c *Cursor[t]) HasRight() bool { return c.Valid() && c.path[len(c.path)-1].right != nil }
// Right moves to the right subtree of c, and returns c.
// If c had no right subtree, it becomes invalid.
func (c *Cursor[T]) Right() *Cursor[T] {
if c.Valid() {
if right := c.path[len(c.path)-1].right; right != nil {
c.path = append(c.path, right)
} else {
c.path = nil // invalidate
}
}
return c
}
// HasParent reports whether c has a parent.
// An invalid cursor has no parent.
func (c *Cursor[T]) HasParent() bool { return c.Valid() && len(c.path) > 1 }
// Up moves to the parent of c, and returns c.
// If c had no parent, it becomes invalid..
func (c *Cursor[T]) Up() *Cursor[T] {
if c.Valid() {
// Note that this may result in c being invalid, if it was already
// pointed at the root of the tree.
c.path = c.path[:len(c.path)-1]
}
return c
}
// Min moves c to the minimum element of its subtree, and returns c.
func (c *Cursor[T]) Min() *Cursor[T] {
if c.Valid() {
min := c.path[len(c.path)-1]
for min.left != nil {
min = min.left
c.path = append(c.path, min)
}
}
return c
}
// Max moves c to the maximum element of its subtree, and returns c.
func (c *Cursor[T]) Max() *Cursor[T] {
if c.Valid() {
max := c.path[len(c.path)-1]
for max.right != nil {
max = max.right
c.path = append(c.path, max)
}
}
return c
}
// Inorder is a range function over each key of the subtree at c in order.
func (c *Cursor[T]) Inorder(yield func(key T) bool) {
if c.Valid() {
c.path[len(c.path)-1].inorder(yield)
}
}