TODO: wordIndexUpperLower 原因: 边界
This commit is contained in:
parent
b4829ba058
commit
5a7a4f2c92
|
@ -1,15 +1,5 @@
|
||||||
package tried
|
package tried
|
||||||
|
|
||||||
type TriedString string
|
|
||||||
|
|
||||||
func (ts TriedString) Size() uint {
|
|
||||||
return uint(len(ts))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ts TriedString) WordIndex(idx uint) uint {
|
|
||||||
return uint(ts[idx]) - 'a'
|
|
||||||
}
|
|
||||||
|
|
||||||
// func (ts TriedString) WordIndex(idx uint) uint {
|
// func (ts TriedString) WordIndex(idx uint) uint {
|
||||||
// w := ts[idx]
|
// w := ts[idx]
|
||||||
// if w >= 'a' && w <= 'z' {
|
// if w >= 'a' && w <= 'z' {
|
||||||
|
@ -21,14 +11,9 @@ func (ts TriedString) WordIndex(idx uint) uint {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
type ObjectIndex interface {
|
|
||||||
WordIndex(idx uint) uint
|
|
||||||
Size() uint
|
|
||||||
}
|
|
||||||
|
|
||||||
type Tried struct {
|
type Tried struct {
|
||||||
root *Node
|
root *Node
|
||||||
datasize uint
|
wiStore *wordIndexStore
|
||||||
}
|
}
|
||||||
|
|
||||||
type Node struct {
|
type Node struct {
|
||||||
|
@ -36,25 +21,34 @@ type Node struct {
|
||||||
value interface{}
|
value interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New 默认 WordIndexLower 意味着只支持小写
|
||||||
func New() *Tried {
|
func New() *Tried {
|
||||||
tried := &Tried{}
|
tried := &Tried{}
|
||||||
tried.root = new(Node)
|
tried.root = new(Node)
|
||||||
tried.datasize = 62
|
|
||||||
|
tried.wiStore = WordIndexDict[WordIndexLower]
|
||||||
return tried
|
return tried
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tried *Tried) wordIndex(w byte) uint {
|
// NewWithWordType 选择单词的类型 WordIndexLower 意味着只支持小写
|
||||||
return uint(w) - 'a'
|
func NewWithWordType(t WordIndexType) *Tried {
|
||||||
|
tried := &Tried{}
|
||||||
|
tried.root = new(Node)
|
||||||
|
|
||||||
|
tried.wiStore = WordIndexDict[t]
|
||||||
|
|
||||||
|
return tried
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tried *Tried) Put(words string, values ...interface{}) {
|
func (tried *Tried) Put(words string, values ...interface{}) {
|
||||||
cur := tried.root
|
cur := tried.root
|
||||||
var n *Node
|
var n *Node
|
||||||
|
|
||||||
for i := 0; i < len(words); i++ {
|
for i := 0; i < len(words); i++ {
|
||||||
w := tried.wordIndex(words[i])
|
w := tried.wiStore.Byte2Index(words[i])
|
||||||
|
|
||||||
if cur.data == nil {
|
if cur.data == nil {
|
||||||
cur.data = make([]*Node, tried.datasize)
|
cur.data = make([]*Node, tried.wiStore.DataSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
if n = cur.data[w]; n == nil {
|
if n = cur.data[w]; n == nil {
|
||||||
|
@ -81,8 +75,9 @@ func (tried *Tried) Put(words string, values ...interface{}) {
|
||||||
func (tried *Tried) Get(words string) interface{} {
|
func (tried *Tried) Get(words string) interface{} {
|
||||||
cur := tried.root
|
cur := tried.root
|
||||||
var n *Node
|
var n *Node
|
||||||
|
|
||||||
for i := 0; i < len(words); i++ {
|
for i := 0; i < len(words); i++ {
|
||||||
w := tried.wordIndex(words[i]) //TODO: 升级Index 函数
|
w := tried.wiStore.Byte2Index(words[i]) //TODO: 升级Index 函数
|
||||||
if n = cur.data[w]; n == nil {
|
if n = cur.data[w]; n == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
152
tree/tried/tried_index.go
Normal file
152
tree/tried/tried_index.go
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
package tried
|
||||||
|
|
||||||
|
var WordIndexDict map[WordIndexType]*wordIndexStore
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
WordIndexDict = make(map[WordIndexType]*wordIndexStore)
|
||||||
|
WordIndexDict[WordIndexLower] = &wordIndexStore{WordIndexLower, wordIndexLower, indexWordLower, 26}
|
||||||
|
WordIndexDict[WordIndexUpper] = &wordIndexStore{WordIndexUpper, wordIndexUpper, indexWordUpper, 26}
|
||||||
|
WordIndexDict[WordIndexDigital] = &wordIndexStore{WordIndexDigital, wordIndexDigital, indexWordDigital, 10}
|
||||||
|
WordIndexDict[WordIndexUpperLower] = &wordIndexStore{WordIndexUpperLower, wordIndexUpperLower, indexWordUpperLower, 52}
|
||||||
|
WordIndexDict[WordIndexLowerDigital] = &wordIndexStore{WordIndexLowerDigital, wordIndexLowerDigital, indexWordLowerDigital, 36}
|
||||||
|
WordIndexDict[WordIndexUpperDigital] = &wordIndexStore{WordIndexUpperDigital, wordIndexUpperDigital, indexWordUpperDigital, 36}
|
||||||
|
WordIndexDict[WordIndexUpperLowerDigital] = &wordIndexStore{WordIndexUpperLowerDigital, wordIndexUpperLowerDigital, indexWordUpperLowerDigital, 62}
|
||||||
|
WordIndexDict[WordIndex256] = &wordIndexStore{WordIndex256, wordIndex256, indexWord256, 256}
|
||||||
|
WordIndexDict[WordIndex32to126] = &wordIndexStore{WordIndex32to126, wordIndex32to126, indexWord32to126, ('~' - ' ' + 1)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WordIndexType 单词统计的类型 eg. WordIndexLower 意味Put的单词只支持小写...
|
||||||
|
type WordIndexType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
_ WordIndexType = iota
|
||||||
|
WordIndexLower
|
||||||
|
WordIndexUpper
|
||||||
|
WordIndexDigital
|
||||||
|
WordIndexUpperLower
|
||||||
|
WordIndexLowerDigital
|
||||||
|
WordIndexUpperDigital
|
||||||
|
WordIndexUpperLowerDigital
|
||||||
|
WordIndex256
|
||||||
|
WordIndex32to126
|
||||||
|
)
|
||||||
|
|
||||||
|
type wordIndexStore struct {
|
||||||
|
Type WordIndexType
|
||||||
|
Byte2Index func(byte) uint
|
||||||
|
Index2Byte func(uint) byte
|
||||||
|
DataSize uint
|
||||||
|
}
|
||||||
|
|
||||||
|
func wordIndexLower(w byte) uint {
|
||||||
|
return uint(w) - 'a'
|
||||||
|
}
|
||||||
|
|
||||||
|
func indexWordLower(w uint) byte {
|
||||||
|
return byte(w) + 'a'
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
func wordIndexUpper(w byte) uint {
|
||||||
|
return uint(w) - 'A'
|
||||||
|
}
|
||||||
|
|
||||||
|
func indexWordUpper(w uint) byte {
|
||||||
|
return byte(w) + 'A'
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
func wordIndexDigital(w byte) uint {
|
||||||
|
return uint(w) - '0'
|
||||||
|
}
|
||||||
|
|
||||||
|
func indexWordDigital(w uint) byte {
|
||||||
|
return byte(w) + '0'
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
func wordIndexUpperLower(w byte) uint {
|
||||||
|
iw := uint(w)
|
||||||
|
if iw > 'a' {
|
||||||
|
return iw - 'a'
|
||||||
|
}
|
||||||
|
return iw - 'A' + 26
|
||||||
|
}
|
||||||
|
|
||||||
|
func indexWordUpperLower(w uint) byte {
|
||||||
|
|
||||||
|
if w >= 26 {
|
||||||
|
return byte(w) + 'A'
|
||||||
|
}
|
||||||
|
return byte(w) + 'a'
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
func wordIndexLowerDigital(w byte) uint {
|
||||||
|
iw := uint(w)
|
||||||
|
if iw > 'a' {
|
||||||
|
return iw - 'a'
|
||||||
|
}
|
||||||
|
return iw - '0' + 26
|
||||||
|
}
|
||||||
|
|
||||||
|
func indexWordLowerDigital(w uint) byte {
|
||||||
|
if w >= 26 {
|
||||||
|
return byte(w) + '0'
|
||||||
|
}
|
||||||
|
return byte(w) + 'a'
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
func wordIndexUpperDigital(w byte) uint {
|
||||||
|
iw := uint(w)
|
||||||
|
if iw > 'A' {
|
||||||
|
return iw - 'A'
|
||||||
|
}
|
||||||
|
return iw - '0' + 26
|
||||||
|
}
|
||||||
|
|
||||||
|
func indexWordUpperDigital(w uint) byte {
|
||||||
|
if w >= 26 {
|
||||||
|
return byte(w) + '0'
|
||||||
|
}
|
||||||
|
return byte(w) + 'a'
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
func wordIndexUpperLowerDigital(w byte) uint {
|
||||||
|
iw := uint(w)
|
||||||
|
if iw > 'a' {
|
||||||
|
return iw - 'a'
|
||||||
|
} else if iw > 'A' {
|
||||||
|
return iw - 'A' + 26
|
||||||
|
}
|
||||||
|
return iw - '0' + 52
|
||||||
|
}
|
||||||
|
|
||||||
|
func indexWordUpperLowerDigital(w uint) byte {
|
||||||
|
if w >= 52 {
|
||||||
|
return byte(w) + '0'
|
||||||
|
} else if w >= 26 {
|
||||||
|
return byte(w) + 'A'
|
||||||
|
}
|
||||||
|
return byte(w) + 'a'
|
||||||
|
}
|
||||||
|
|
||||||
|
// wordIndex256 all byte
|
||||||
|
func wordIndex256(w byte) uint {
|
||||||
|
return uint(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func indexWord256(w uint) byte {
|
||||||
|
return byte(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
// wordIndex32to126 空格-~ 0-9 a-z A-Z 符号等
|
||||||
|
func wordIndex32to126(w byte) uint {
|
||||||
|
return uint(w) - ' '
|
||||||
|
}
|
||||||
|
|
||||||
|
func indexWord32to126(w uint) byte {
|
||||||
|
return byte(w) + ' '
|
||||||
|
}
|
|
@ -1,11 +1,44 @@
|
||||||
package tried
|
package tried
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/gob"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/Pallinder/go-randomdata"
|
"github.com/Pallinder/go-randomdata"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestTried_NewWith(t *testing.T) {
|
||||||
|
tried := NewWithWordType(WordIndex32to126)
|
||||||
|
words := "~ 23fd "
|
||||||
|
tried.Put(words)
|
||||||
|
if tried.Get(words) == nil {
|
||||||
|
t.Error("should be not nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
tried = NewWithWordType(WordIndexLower)
|
||||||
|
words = "az"
|
||||||
|
tried.Put(words)
|
||||||
|
if tried.Get(words) == nil {
|
||||||
|
t.Error("should be not nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
tried = NewWithWordType(WordIndexUpper)
|
||||||
|
words = "AZ"
|
||||||
|
tried.Put(words)
|
||||||
|
if tried.Get(words) == nil {
|
||||||
|
t.Error("should be not nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
tried = NewWithWordType(WordIndexUpperLower)
|
||||||
|
words = "AZazsdfsd"
|
||||||
|
tried.Put(words)
|
||||||
|
if tried.Get(words) == nil {
|
||||||
|
t.Error("should be not nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestTried_PutAndGet1(t *testing.T) {
|
func TestTried_PutAndGet1(t *testing.T) {
|
||||||
tried := New()
|
tried := New()
|
||||||
|
|
||||||
|
@ -72,20 +105,49 @@ func TestTried_Traversal(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TesStoreData(t *testing.T) {
|
||||||
|
var l []string
|
||||||
|
const N = 1000000
|
||||||
|
for i := 0; i < N; i++ {
|
||||||
|
var content []rune
|
||||||
|
for c := 0; c < randomdata.Number(5, 15); c++ {
|
||||||
|
char := randomdata.Number(0, 26) + 'a'
|
||||||
|
content = append(content, rune(byte(char)))
|
||||||
|
}
|
||||||
|
l = append(l, (string(content)))
|
||||||
|
}
|
||||||
|
|
||||||
|
var result bytes.Buffer
|
||||||
|
encoder := gob.NewEncoder(&result)
|
||||||
|
encoder.Encode(l)
|
||||||
|
lbytes := result.Bytes()
|
||||||
|
f, _ := os.OpenFile("tried.log", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
|
||||||
|
f.Write(lbytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Load() []string {
|
||||||
|
var result []string
|
||||||
|
f, _ := os.Open("tried.log")
|
||||||
|
gob.NewDecoder(f).Decode(&result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkTried_Put(b *testing.B) {
|
func BenchmarkTried_Put(b *testing.B) {
|
||||||
|
|
||||||
var data []string
|
var data []string
|
||||||
b.N = 1000000
|
b.N = 1000000
|
||||||
count := 10
|
count := 10
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
// for i := 0; i < b.N; i++ {
|
||||||
var content []rune
|
// var content []rune
|
||||||
for c := 0; c < randomdata.Number(5, 15); c++ {
|
// for c := 0; c < randomdata.Number(5, 15); c++ {
|
||||||
char := randomdata.Number(0, 26) + 'a'
|
// char := randomdata.Number(0, 26) + 'a'
|
||||||
content = append(content, rune(byte(char)))
|
// content = append(content, rune(byte(char)))
|
||||||
}
|
// }
|
||||||
data = append(data, (string(content)))
|
// data = append(data, (string(content)))
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
data = Load()
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
b.N = b.N * count
|
b.N = b.N * count
|
||||||
|
@ -98,19 +160,20 @@ func BenchmarkTried_Put(b *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkTried_Get(b *testing.B) {
|
func BenchmarkTried_Get(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
var data []string
|
var data []string
|
||||||
b.N = 1000000
|
b.N = 1000000
|
||||||
count := 10
|
count := 10
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
// for i := 0; i < b.N; i++ {
|
||||||
var content []rune
|
// var content []rune
|
||||||
for c := 0; c < randomdata.Number(5, 15); c++ {
|
// for c := 0; c < randomdata.Number(5, 15); c++ {
|
||||||
char := randomdata.Number(0, 26) + 'a'
|
// char := randomdata.Number(0, 26) + 'a'
|
||||||
content = append(content, rune(byte(char)))
|
// content = append(content, rune(byte(char)))
|
||||||
}
|
// }
|
||||||
data = append(data, string(content))
|
// data = append(data, string(content))
|
||||||
}
|
// }
|
||||||
|
data = Load()
|
||||||
|
|
||||||
b.N = b.N * count
|
b.N = b.N * count
|
||||||
|
|
||||||
|
@ -119,7 +182,7 @@ func BenchmarkTried_Get(b *testing.B) {
|
||||||
tried.Put(v)
|
tried.Put(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
b.ResetTimer()
|
b.StartTimer()
|
||||||
for c := 0; c < count; c++ {
|
for c := 0; c < count; c++ {
|
||||||
for _, v := range data {
|
for _, v := range data {
|
||||||
tried.Get(v)
|
tried.Get(v)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user