Search Apps Documentation Source Content File Folder Download Copy

node.gno

12.54 Kb ยท 489 lines
  1package avl
  2
  3//----------------------------------------
  4// Node
  5
  6// Node represents a node in an AVL tree.
  7type Node struct {
  8	key       string      // key is the unique identifier for the node.
  9	value     interface{} // value is the data stored in the node.
 10	height    int8        // height is the height of the node in the tree.
 11	size      int         // size is the number of nodes in the subtree rooted at this node.
 12	leftNode  *Node       // leftNode is the left child of the node.
 13	rightNode *Node       // rightNode is the right child of the node.
 14}
 15
 16// NewNode creates a new node with the given key and value.
 17func NewNode(key string, value interface{}) *Node {
 18	return &Node{
 19		key:    key,
 20		value:  value,
 21		height: 0,
 22		size:   1,
 23	}
 24}
 25
 26// Size returns the size of the subtree rooted at the node.
 27func (node *Node) Size() int {
 28	if node == nil {
 29		return 0
 30	}
 31	return node.size
 32}
 33
 34// IsLeaf checks if the node is a leaf node (has no children).
 35func (node *Node) IsLeaf() bool {
 36	return node.height == 0
 37}
 38
 39// Key returns the key of the node.
 40func (node *Node) Key() string {
 41	return node.key
 42}
 43
 44// Value returns the value of the node.
 45func (node *Node) Value() interface{} {
 46	return node.value
 47}
 48
 49// _copy creates a copy of the node (excluding value).
 50func (node *Node) _copy() *Node {
 51	if node.height == 0 {
 52		panic("Why are you copying a value node?")
 53	}
 54	return &Node{
 55		key:       node.key,
 56		height:    node.height,
 57		size:      node.size,
 58		leftNode:  node.leftNode,
 59		rightNode: node.rightNode,
 60	}
 61}
 62
 63// Has checks if a node with the given key exists in the subtree rooted at the node.
 64func (node *Node) Has(key string) (has bool) {
 65	if node == nil {
 66		return false
 67	}
 68	if node.key == key {
 69		return true
 70	}
 71	if node.height == 0 {
 72		return false
 73	}
 74	if key < node.key {
 75		return node.getLeftNode().Has(key)
 76	}
 77	return node.getRightNode().Has(key)
 78}
 79
 80// Get searches for a node with the given key in the subtree rooted at the node
 81// and returns its index, value, and whether it exists.
 82func (node *Node) Get(key string) (index int, value interface{}, exists bool) {
 83	if node == nil {
 84		return 0, nil, false
 85	}
 86
 87	if node.height == 0 {
 88		if node.key == key {
 89			return 0, node.value, true
 90		}
 91		if node.key < key {
 92			return 1, nil, false
 93		}
 94		return 0, nil, false
 95	}
 96
 97	if key < node.key {
 98		return node.getLeftNode().Get(key)
 99	}
100
101	rightNode := node.getRightNode()
102	index, value, exists = rightNode.Get(key)
103	index += node.size - rightNode.size
104	return index, value, exists
105}
106
107// GetByIndex retrieves the key-value pair of the node at the given index
108// in the subtree rooted at the node.
109func (node *Node) GetByIndex(index int) (key string, value interface{}) {
110	if node.height == 0 {
111		if index == 0 {
112			return node.key, node.value
113		}
114		panic("GetByIndex asked for invalid index")
115	}
116	// TODO: could improve this by storing the sizes
117	leftNode := node.getLeftNode()
118	if index < leftNode.size {
119		return leftNode.GetByIndex(index)
120	}
121	return node.getRightNode().GetByIndex(index - leftNode.size)
122}
123
124// Set inserts a new node with the given key-value pair into the subtree rooted at the node,
125// and returns the new root of the subtree and whether an existing node was updated.
126//
127// XXX consider a better way to do this... perhaps split Node from Node.
128func (node *Node) Set(key string, value interface{}) (newSelf *Node, updated bool) {
129	if node == nil {
130		return NewNode(key, value), false
131	}
132
133	if node.height == 0 {
134		return node.setLeaf(key, value)
135	}
136
137	node = node._copy()
138	if key < node.key {
139		node.leftNode, updated = node.getLeftNode().Set(key, value)
140	} else {
141		node.rightNode, updated = node.getRightNode().Set(key, value)
142	}
143
144	if updated {
145		return node, updated
146	}
147
148	node.calcHeightAndSize()
149	return node.balance(), updated
150}
151
152// setLeaf inserts a new leaf node with the given key-value pair into the subtree rooted at the node,
153// and returns the new root of the subtree and whether an existing node was updated.
154func (node *Node) setLeaf(key string, value interface{}) (newSelf *Node, updated bool) {
155	if key == node.key {
156		return NewNode(key, value), true
157	}
158
159	if key < node.key {
160		return &Node{
161			key:       node.key,
162			height:    1,
163			size:      2,
164			leftNode:  NewNode(key, value),
165			rightNode: node,
166		}, false
167	}
168
169	return &Node{
170		key:       key,
171		height:    1,
172		size:      2,
173		leftNode:  node,
174		rightNode: NewNode(key, value),
175	}, false
176}
177
178// Remove deletes the node with the given key from the subtree rooted at the node.
179// returns the new root of the subtree, the new leftmost leaf key (if changed),
180// the removed value and the removal was successful.
181func (node *Node) Remove(key string) (
182	newNode *Node, newKey string, value interface{}, removed bool,
183) {
184	if node == nil {
185		return nil, "", nil, false
186	}
187	if node.height == 0 {
188		if key == node.key {
189			return nil, "", node.value, true
190		}
191		return node, "", nil, false
192	}
193	if key < node.key {
194		var newLeftNode *Node
195		newLeftNode, newKey, value, removed = node.getLeftNode().Remove(key)
196		if !removed {
197			return node, "", value, false
198		}
199		if newLeftNode == nil { // left node held value, was removed
200			return node.rightNode, node.key, value, true
201		}
202		node = node._copy()
203		node.leftNode = newLeftNode
204		node.calcHeightAndSize()
205		node = node.balance()
206		return node, newKey, value, true
207	}
208
209	var newRightNode *Node
210	newRightNode, newKey, value, removed = node.getRightNode().Remove(key)
211	if !removed {
212		return node, "", value, false
213	}
214	if newRightNode == nil { // right node held value, was removed
215		return node.leftNode, "", value, true
216	}
217	node = node._copy()
218	node.rightNode = newRightNode
219	if newKey != "" {
220		node.key = newKey
221	}
222	node.calcHeightAndSize()
223	node = node.balance()
224	return node, "", value, true
225}
226
227// getLeftNode returns the left child of the node.
228func (node *Node) getLeftNode() *Node {
229	return node.leftNode
230}
231
232// getRightNode returns the right child of the node.
233func (node *Node) getRightNode() *Node {
234	return node.rightNode
235}
236
237// rotateRight performs a right rotation on the node and returns the new root.
238// NOTE: overwrites node
239// TODO: optimize balance & rotate
240func (node *Node) rotateRight() *Node {
241	node = node._copy()
242	l := node.getLeftNode()
243	_l := l._copy()
244
245	_lrCached := _l.rightNode
246	_l.rightNode = node
247	node.leftNode = _lrCached
248
249	node.calcHeightAndSize()
250	_l.calcHeightAndSize()
251
252	return _l
253}
254
255// rotateLeft performs a left rotation on the node and returns the new root.
256// NOTE: overwrites node
257// TODO: optimize balance & rotate
258func (node *Node) rotateLeft() *Node {
259	node = node._copy()
260	r := node.getRightNode()
261	_r := r._copy()
262
263	_rlCached := _r.leftNode
264	_r.leftNode = node
265	node.rightNode = _rlCached
266
267	node.calcHeightAndSize()
268	_r.calcHeightAndSize()
269
270	return _r
271}
272
273// calcHeightAndSize updates the height and size of the node based on its children.
274// NOTE: mutates height and size
275func (node *Node) calcHeightAndSize() {
276	node.height = maxInt8(node.getLeftNode().height, node.getRightNode().height) + 1
277	node.size = node.getLeftNode().size + node.getRightNode().size
278}
279
280// calcBalance calculates the balance factor of the node.
281func (node *Node) calcBalance() int {
282	return int(node.getLeftNode().height) - int(node.getRightNode().height)
283}
284
285// balance balances the subtree rooted at the node and returns the new root.
286// NOTE: assumes that node can be modified
287// TODO: optimize balance & rotate
288func (node *Node) balance() (newSelf *Node) {
289	balance := node.calcBalance()
290	if balance >= -1 {
291		return node
292	}
293	if balance > 1 {
294		if node.getLeftNode().calcBalance() >= 0 {
295			// Left Left Case
296			return node.rotateRight()
297		}
298		// Left Right Case
299		left := node.getLeftNode()
300		node.leftNode = left.rotateLeft()
301		return node.rotateRight()
302	}
303
304	if node.getRightNode().calcBalance() <= 0 {
305		// Right Right Case
306		return node.rotateLeft()
307	}
308
309	// Right Left Case
310	right := node.getRightNode()
311	node.rightNode = right.rotateRight()
312	return node.rotateLeft()
313}
314
315// Shortcut for TraverseInRange.
316func (node *Node) Iterate(start, end string, cb func(*Node) bool) bool {
317	return node.TraverseInRange(start, end, true, true, cb)
318}
319
320// Shortcut for TraverseInRange.
321func (node *Node) ReverseIterate(start, end string, cb func(*Node) bool) bool {
322	return node.TraverseInRange(start, end, false, true, cb)
323}
324
325// TraverseInRange traverses all nodes, including inner nodes.
326// Start is inclusive and end is exclusive when ascending,
327// Start and end are inclusive when descending.
328// Empty start and empty end denote no start and no end.
329// If leavesOnly is true, only visit leaf nodes.
330// NOTE: To simulate an exclusive reverse traversal,
331// just append 0x00 to start.
332func (node *Node) TraverseInRange(start, end string, ascending bool, leavesOnly bool, cb func(*Node) bool) bool {
333	if node == nil {
334		return false
335	}
336	afterStart := (start == "" || start < node.key)
337	startOrAfter := (start == "" || start <= node.key)
338	beforeEnd := false
339	if ascending {
340		beforeEnd = (end == "" || node.key < end)
341	} else {
342		beforeEnd = (end == "" || node.key <= end)
343	}
344
345	// Run callback per inner/leaf node.
346	stop := false
347	if (!node.IsLeaf() && !leavesOnly) ||
348		(node.IsLeaf() && startOrAfter && beforeEnd) {
349		stop = cb(node)
350		if stop {
351			return stop
352		}
353	}
354	if node.IsLeaf() {
355		return stop
356	}
357
358	if ascending {
359		// check lower nodes, then higher
360		if afterStart {
361			stop = node.getLeftNode().TraverseInRange(start, end, ascending, leavesOnly, cb)
362		}
363		if stop {
364			return stop
365		}
366		if beforeEnd {
367			stop = node.getRightNode().TraverseInRange(start, end, ascending, leavesOnly, cb)
368		}
369	} else {
370		// check the higher nodes first
371		if beforeEnd {
372			stop = node.getRightNode().TraverseInRange(start, end, ascending, leavesOnly, cb)
373		}
374		if stop {
375			return stop
376		}
377		if afterStart {
378			stop = node.getLeftNode().TraverseInRange(start, end, ascending, leavesOnly, cb)
379		}
380	}
381
382	return stop
383}
384
385// TraverseByOffset traverses all nodes, including inner nodes.
386// A limit of math.MaxInt means no limit.
387func (node *Node) TraverseByOffset(offset, limit int, ascending bool, leavesOnly bool, cb func(*Node) bool) bool {
388	if node == nil {
389		return false
390	}
391
392	// fast paths. these happen only if TraverseByOffset is called directly on a leaf.
393	if limit <= 0 || offset >= node.size {
394		return false
395	}
396	if node.IsLeaf() {
397		if offset > 0 {
398			return false
399		}
400		return cb(node)
401	}
402
403	// go to the actual recursive function.
404	return node.traverseByOffset(offset, limit, ascending, leavesOnly, cb)
405}
406
407// TraverseByOffset traverses the subtree rooted at the node by offset and limit,
408// in either ascending or descending order, and applies the callback function to each traversed node.
409// If leavesOnly is true, only leaf nodes are visited.
410func (node *Node) traverseByOffset(offset, limit int, ascending bool, leavesOnly bool, cb func(*Node) bool) bool {
411	// caller guarantees: offset < node.size; limit > 0.
412	if !leavesOnly {
413		if cb(node) {
414			return true // Stop traversal if callback returns true
415		}
416	}
417	first, second := node.getLeftNode(), node.getRightNode()
418	if !ascending {
419		first, second = second, first
420	}
421	if first.IsLeaf() {
422		// either run or skip, based on offset
423		if offset > 0 {
424			offset--
425		} else {
426			if cb(first) {
427				return true // Stop traversal if callback returns true
428			}
429			limit--
430			if limit <= 0 {
431				return true // Stop traversal when limit is reached
432			}
433		}
434	} else {
435		// possible cases:
436		// 1 the offset given skips the first node entirely
437		// 2 the offset skips none or part of the first node, but the limit requires some of the second node.
438		// 3 the offset skips none or part of the first node, and the limit stops our search on the first node.
439		if offset >= first.size {
440			offset -= first.size // 1
441		} else {
442			if first.traverseByOffset(offset, limit, ascending, leavesOnly, cb) {
443				return true
444			}
445			// number of leaves which could actually be called from inside
446			delta := first.size - offset
447			offset = 0
448			if delta >= limit {
449				return true // 3
450			}
451			limit -= delta // 2
452		}
453	}
454
455	// because of the caller guarantees and the way we handle the first node,
456	// at this point we know that limit > 0 and there must be some values in
457	// this second node that we include.
458
459	// => if the second node is a leaf, it has to be included.
460	if second.IsLeaf() {
461		return cb(second)
462	}
463	// => if it is not a leaf, it will still be enough to recursively call this
464	// function with the updated offset and limit
465	return second.traverseByOffset(offset, limit, ascending, leavesOnly, cb)
466}
467
468// Only used in testing...
469func (node *Node) lmd() *Node {
470	if node.height == 0 {
471		return node
472	}
473	return node.getLeftNode().lmd()
474}
475
476// Only used in testing...
477func (node *Node) rmd() *Node {
478	if node.height == 0 {
479		return node
480	}
481	return node.getRightNode().rmd()
482}
483
484func maxInt8(a, b int8) int8 {
485	if a > b {
486		return a
487	}
488	return b
489}