-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtreap.go
More file actions
164 lines (140 loc) · 3.6 KB
/
treap.go
File metadata and controls
164 lines (140 loc) · 3.6 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
// Package treap provides a balanced binary search tree
// by using binary heap properties and randomization.
package treap
import (
"math"
"math/rand"
"time"
)
const (
// Random priorities in the Treap will be in the range of [1, MaxInt64].
maxPriority = math.MaxInt64
minPriority = 1
// The priority given to Treap nodes during deletion.
deletePriority = 0
)
// Treap is a balanced binary search tree.
type Treap struct {
root *node
}
// node represents a value and its priority in a Treap.
type node struct {
value string
priority int64
left *node
right *node
}
// NewTreap returns a new Treap.
func NewTreap() *Treap {
return &Treap{}
}
// Search returns true if the given value is in the Treap.
// Otherwise, returns false.
func (t *Treap) Search(value string) bool {
if t.root == nil {
return false
}
return binarySearch(t.root, value) != nil
}
// Insert inserts the given value into the Treap.
func (t *Treap) Insert(value string) {
rand.Seed(time.Now().UnixNano())
t.root = insert(t.root, value,
rand.Int63n(maxPriority-minPriority)+minPriority)
}
// insert inserts a node with the passed value and priority into the Treap.
func insert(n *node, value string, priority int64) *node {
if n == nil {
return &node{
value: value,
priority: priority,
}
}
if value == n.value {
return n
} else if value < n.value {
n.left = insert(n.left, value, priority)
if n.priority < n.left.priority {
n = rotateRight(n, n.left)
}
} else {
n.right = insert(n.right, value, priority)
if n.priority < n.right.priority {
n = rotateLeft(n, n.right)
}
}
return n
}
// Delete deletes the given value from the Treap.
func (t *Treap) Delete(value string) {
t.root = delete(t.root, value)
}
// delete finds and deletes the node with the given value from the Treap.
func delete(n *node, value string) *node {
if n == nil {
return nil
}
// delete the node with value after it's been rotated down to a leaf
if n.left == nil && n.right == nil && n.value == value {
return nil
}
if n.value == value {
n.priority = deletePriority
if n.right == nil && n.left != nil {
pivot := rotateRight(n, n.left)
pivot.right = delete(n, value)
return pivot
} else if n.left == nil && n.right != nil {
pivot := rotateLeft(n, n.right)
pivot.left = delete(n, value)
return pivot
} else if n.right.priority > n.left.priority {
pivot := rotateLeft(n, n.right)
pivot.left = delete(n, value)
return pivot
} else {
pivot := rotateRight(n, n.left)
pivot.right = delete(n, value)
return pivot
}
}
if value < n.value {
n.left = delete(n.left, value)
} else {
n.right = delete(n.right, value)
}
return n
}
// binarySearch performs a binary search starting from the
// passed node for the passed value.
// If the passed value is found, a pointer to the node with
// the value is returned. Otherwise, nil is returned.
func binarySearch(n *node, value string) *node {
for n != nil {
if value == n.value {
return n
}
if value < n.value {
n = n.left
} else {
n = n.right
}
}
return nil
}
// rotateRight does a tree rotation to the right given the passed root and pivot.
// After the rotation, the root will be the right child of the pivot.
// The pivot will be returned.
func rotateRight(root, pivot *node) *node {
root.left = pivot.right
pivot.right = root
return pivot
}
// rotateLeft does a tree rotation to the left given the passed root and pivot.
// After the rotation, the root will be the left child of the pivot.
// The pivot will be returned.
func rotateLeft(root, pivot *node) *node {
root.right = pivot.left
pivot.left = root
return pivot
}