-
Notifications
You must be signed in to change notification settings - Fork 5
/
tree.go
140 lines (118 loc) · 3.19 KB
/
tree.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
package flattree
import (
"errors"
"math/bits"
)
// Index returns the index of a node given its depth and offset
func Index(depth, offset uint64) uint64 {
return (offset << (depth + 1)) | ((1 << depth) - 1)
}
// Depth returns the depth of a given node
func Depth(n uint64) uint64 {
return uint64(bits.TrailingZeros64(^n))
}
// Offset returns the offset of a given node
// The offset is the distance from the left edge of the tree
func Offset(n uint64) uint64 {
if isEven(n) {
return n / 2
}
return n >> (Depth(n) + 1)
}
// Parent returns the parent node of the provided node
func Parent(n uint64) uint64 {
return Index(Depth(n)+1, Offset(n)/2)
}
// Sibling returns the sibling of the provided node
func Sibling(n uint64) uint64 {
return Index(Depth(n), Offset(n)^1)
}
// Uncle returns the parent's sibling of the provided node
func Uncle(n uint64) uint64 {
return Index(Depth(n)+1, Offset(Parent(n))^1)
}
// Children returns the children of the provided node, if it exists
// Returns the children and a bool indicating if they exist
func Children(n uint64) (left uint64, right uint64, exists bool) {
if isEven(n) {
return 0, 0, false
}
depth := Depth(n)
offset := Offset(n) * 2
left = Index(depth-1, offset)
right = Index(depth-1, offset+1)
return left, right, true
}
// LeftChild returns the left child of the provided node, if it exists
// Returns the left child and a bool indicating if it exists
func LeftChild(n uint64) (uint64, bool) {
if isEven(n) {
return 0, false
}
return Index(Depth(n)-1, Offset(n)*2), true
}
// RightChild returns the left child of the provided node, if it exists
// Returns the right child and a bool indicating if it exists
func RightChild(n uint64) (uint64, bool) {
if isEven(n) {
return 0, false
}
return Index(Depth(n)-1, (Offset(n)*2)+1), true
}
// Spans returns the left and right most nodes in the tree which the provided node spans
func Spans(n uint64) (left uint64, right uint64) {
if isEven(n) {
return n, n
}
depth := Depth(n)
offset := Offset(n)
left = offset * (2 << depth)
right = (offset+1)*(2<<depth) - 2
return
}
// LeftSpan returns the left most node in the tree which the provided node spans
func LeftSpan(n uint64) uint64 {
if isEven(n) {
return n
}
return Offset(n) * (2 << Depth(n))
}
// RightSpan returns the right most node in the tree which the provided node spans
func RightSpan(n uint64) uint64 {
if isEven(n) {
return n
}
return (Offset(n)+1)*(2<<Depth(n)) - 2
}
// Count returns the number of nodes under the given node, including the provided node itself
func Count(n uint64) uint64 {
return (2 << Depth(n)) - 1
}
// FullRoots returns a list of all roots less than the provided index
// A root is a subtrees where all nodes have either 2 or 0 children
func FullRoots(index uint64) (roots []uint64, err error) {
roots = []uint64{}
if !isEven(index) {
err = errors.New("odd index passed to FullRoots()")
return
}
index /= 2
offset := uint64(0)
factor := uint64(1)
for {
if index == 0 {
return
}
for uint64(factor*2) <= index {
factor *= 2
}
root := offset + factor - 1
roots = append(roots, root)
offset += 2 * factor
index -= factor
factor = 1
}
}
func isEven(n uint64) bool {
return n%2 == 0
}