-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtrie.go
149 lines (122 loc) · 2.43 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
package trie
import "errors"
const (
trieMaxQueueSize = 300
)
var (
ErrNotInTable = errors.New("not in character table predefined")
ErrDuplicate = errors.New("duplicate insert")
)
type TrieValue interface {
}
type TrieNode struct {
Value interface{}
failed_clue *TrieNode
next []*TrieNode
}
type TrieTree struct {
root TrieNode
branch uint16
keynum int
table [256]uint16
}
//creat a trie tree, table is the character set predefined, not duplicate
func NewTrieTree(table []byte) *TrieTree {
tt := new(TrieTree)
for i := 0; i < 256; i++ {
tt.table[i] = 0xffff
}
for i, c := range table {
tt.table[c] = uint16(i)
}
tt.branch = uint16(len(table))
return tt
}
//inster a key-value pair
//return (nil, ErrNotInTable), if key with character not in set
//return the node and ErrNotInTable, if key is inserted dupliced
func (tt *TrieTree) Insert(key []byte, value interface{}) (*TrieNode, error) {
p := &tt.root
for _, c := range key {
index := tt.table[c]
if index >= tt.branch {
return nil, ErrNotInTable
}
if p.next == nil {
p.next = make([]*TrieNode, tt.branch)
}
if p.next[index] == nil {
p.next[index] = new(TrieNode)
}
p = p.next[index]
}
if p.Value != nil {
return p, ErrDuplicate
}
p.Value = value
tt.keynum++
return p, nil
}
//call BuileClue after insert all keys
func (tt *TrieTree) BuileClue() {
root := &tt.root
var head, tail int
var q [trieMaxQueueSize]*TrieNode
q[head] = root
head++
for head != tail {
p := q[tail]
tail = (tail + 1) % trieMaxQueueSize
if p.next == nil {
continue
}
for c, t := range p.next {
if t == nil {
continue
}
if p == root {
t.failed_clue = root
q[head] = t
head = (head + 1) % trieMaxQueueSize
continue
}
tt := p.failed_clue
for tt != nil {
if tt.next != nil && tt.next[c] != nil {
t.failed_clue = tt.next[c]
break
}
tt = tt.failed_clue
}
if tt == nil {
t.failed_clue = root
}
q[head] = t
head = (head + 1) % trieMaxQueueSize
}
}
}
//return the value if a key was found in block, otherwise return nil
func (tt *TrieTree) Query(block []byte) interface{} {
root := &tt.root
p := root
for _, c := range block {
index := tt.table[c]
if index >= tt.branch {
p = root
continue
}
for p.next == nil {
if p == root {
break
}
p = p.failed_clue
}
p = p.next[index]
if p == nil {
p = root
}
return p.Value
}
return nil
}