mirror of
https://github.com/nadoo/glider.git
synced 2025-04-21 11:42:08 +08:00
129 lines
2.0 KiB
Go
129 lines
2.0 KiB
Go
// Static trie
|
|
package trie
|
|
|
|
import (
|
|
"strings"
|
|
)
|
|
|
|
type cast map[rune]*next
|
|
|
|
type next struct {
|
|
*node
|
|
str *string
|
|
}
|
|
|
|
type node struct {
|
|
c cast
|
|
end bool
|
|
}
|
|
|
|
type Trie struct {
|
|
root *node
|
|
}
|
|
|
|
func newNode() *node {
|
|
return &node{
|
|
c: cast{},
|
|
end: false,
|
|
}
|
|
}
|
|
|
|
func New(dict []string) (trie *Trie) {
|
|
var t Trie
|
|
var ok bool
|
|
var p *node
|
|
t.root = newNode()
|
|
for _, d := range dict {
|
|
p = t.root
|
|
for i, r := range d {
|
|
_, ok = p.c[r]
|
|
if !ok {
|
|
n := next{
|
|
node: newNode(),
|
|
str: nil,
|
|
}
|
|
p.c[r] = &n
|
|
}
|
|
p = p.c[r].node
|
|
if i == len(d)-1 {
|
|
p.end = true
|
|
}
|
|
}
|
|
}
|
|
//make jump
|
|
makeJump(t.root)
|
|
return &t
|
|
}
|
|
|
|
func fastJump(from *next, to *next, str *string) {
|
|
from.str = str
|
|
from.node = to.node
|
|
}
|
|
|
|
func _makeJump(cur *next, from *next, builder *strings.Builder) {
|
|
var fork bool
|
|
if cur.node.end || len(cur.node.c) > 1 {
|
|
if builder.Len() > 1 {
|
|
s := builder.String()
|
|
fastJump(from, cur, &s)
|
|
}
|
|
fork = true
|
|
}
|
|
for k := range cur.node.c {
|
|
child := cur.node.c[k]
|
|
if fork {
|
|
from = child
|
|
builder = new(strings.Builder)
|
|
}
|
|
builder.WriteRune(k)
|
|
_makeJump(child, from, builder)
|
|
}
|
|
}
|
|
|
|
func makeJump(root *node) {
|
|
//DFS
|
|
for k := range root.c {
|
|
builder := new(strings.Builder)
|
|
builder.WriteRune(k)
|
|
_makeJump(root.c[k], root.c[k], builder)
|
|
}
|
|
}
|
|
|
|
func (t *Trie) Match(str string) (prefix string) {
|
|
var builder strings.Builder
|
|
var runes = []rune(str)
|
|
var length = len(runes)
|
|
p := t.root
|
|
for i := 0; i < length; i++ {
|
|
r := runes[i]
|
|
tmp, ok := p.c[r]
|
|
if !ok {
|
|
return
|
|
}
|
|
if tmp.str == nil {
|
|
builder.WriteRune(r)
|
|
} else {
|
|
if lenTmp := len(*tmp.str); builder.Len()+lenTmp <= length {
|
|
if string(runes[i:lenTmp+i]) == *tmp.str {
|
|
builder.WriteString(*tmp.str)
|
|
i += len(*tmp.str) - 1
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if tmp.node.end {
|
|
if builder.Len() <= length {
|
|
prefix = builder.String()
|
|
if len(prefix) == length {
|
|
break
|
|
}
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
p = tmp.node
|
|
}
|
|
return
|
|
}
|