-
Notifications
You must be signed in to change notification settings - Fork 0
/
trie.go
158 lines (131 loc) · 3 KB
/
trie.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
// Copyright 2019 Pavel Knoblokh. All rights reserved.
// Use of this source code is governed by MIT License
// that can be found in the LICENSE file.
// Package trie implements a thread-safe trie, also known as
// digital tree or prefix tree. It can be used as a drop-in
// replacement for usual Go maps with string keys.
package trie
import "sync"
// A Trie is an ordered tree data structure.
type Trie struct {
root *node
size int
nnum int
mu sync.RWMutex
}
type node struct {
symbol rune
parent *node
children map[rune]*node
data interface{}
}
// NewTrie creates a new empty trie.
func NewTrie() *Trie {
return &Trie{
root: &node{
children: make(map[rune]*node),
},
nnum: 1,
}
}
// Insert adds or replaces the data stored at the given key.
func (trie *Trie) Insert(key string, data interface{}) {
trie.mu.Lock()
n := trie.root
for _, r := range key {
c := n.children[r]
if c == nil {
c = &node{
symbol: r,
parent: n,
children: make(map[rune]*node),
}
n.children[r] = c
trie.nnum++
}
n = c
}
n.data = data
trie.size++
trie.mu.Unlock()
}
// Search returns the data stored at the given key.
func (trie *Trie) Search(key string) interface{} {
trie.mu.RLock()
defer trie.mu.RUnlock()
n := trie.root.findNode(key)
if n == nil {
return nil
}
return n.data
}
// WithPrefix returns the map of all the keys and
// their corresponding data for the given key prefix.
func (trie *Trie) WithPrefix(prefix string) map[string]interface{} {
results := make(map[string]interface{})
trie.mu.RLock()
defer trie.mu.RUnlock()
n := trie.root.findNode(prefix)
if n == nil {
return results
}
if n.data != nil {
results[prefix] = n.data
}
var findResults func(*node, string)
findResults = func(n *node, prefix string) {
for r, c := range n.children {
childPrefix := prefix + string(r)
if c.data != nil {
results[childPrefix] = c.data
}
findResults(c, childPrefix)
}
}
findResults(n, prefix)
return results
}
// Delete removes the data stored at the given key and
// returns true on success and false if the key wasn't
// previously set.
func (trie *Trie) Delete(key string) bool {
trie.mu.Lock()
defer trie.mu.Unlock()
n := trie.root.findNode(key)
if n == nil || n.data == nil {
return false
}
n.data = nil
for n.data == nil && len(n.children) == 0 && n.parent != nil {
parent := n.parent
delete(parent.children, n.symbol)
n.parent = nil
n = parent
trie.nnum--
}
trie.size--
return true
}
// Len returns the total number of keys stored in the trie.
func (trie *Trie) Len() int {
trie.mu.RLock()
defer trie.mu.RUnlock()
return trie.size
}
// NodeNum returns the total number of internal nodes
// in the trie, which can be useful for debugging.
func (trie *Trie) NodeNum() int {
trie.mu.RLock()
defer trie.mu.RUnlock()
return trie.nnum
}
// Ensure it is called inside the mutex lock
func (n *node) findNode(key string) *node {
for _, r := range key {
n = n.children[r]
if n == nil {
return nil
}
}
return n
}