上卷 程序设计
中卷 标准库
- bufio 1.18
- bytes 1.18
- io 1.18
- container 1.18
- encoding 1.18
- crypto 1.18
- hash 1.18
- index 1.18
- sort 1.18
- context 1.18
- database 1.18
- connection
- query
- queryrow
- exec
- prepare
- transaction
- scan & null
- context
- tcp
- udp
- http
- server
- handler
- client
- h2、tls
- url
- rpc
- exec
- signal
- embed 1.18
- plugin 1.18
- reflect 1.18
- runtime 1.18
- KeepAlived
- ReadMemStats
- SetFinalizer
- Stack
- sync 1.18
- atomic
- mutex
- rwmutex
- waitgroup
- cond
- once
- map
- pool
- copycheck
- nocopy
- unsafe 1.18
- fmt 1.18
- log 1.18
- math 1.18
- time 1.18
- timer
下卷 运行时
源码剖析
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
index 1.18
suffixarray
后缀数组(suffix array)可用于解决最长公共子串、多模式匹配、最长回文串、全文搜索等问题。相比于后缀树(suffix tree),更易于实现,且占用内存更少。
不过标准库的实现有些简单,仅支持全文检索。
package main import ( "fmt" "index/suffixarray" ) func main() { s := `abcdefgabxx` sub := `ab` index := suffixarray.New([]byte(s)) fmt.Println(index.Lookup([]byte(sub), 10)) } // [0 7]
支持正则表达式。和 Lookup
不同, FindAllIndex
结果是排序过的。
package main import ( "fmt" "index/suffixarray" "regexp" ) func main() { s := `abcdefgabxxs` index := suffixarray.New([]byte(s)) r, _ := regexp.Compile(`ab\w`) fmt.Println(index.FindAllIndex(r, -1)) } // [[0 3] [7 10]]
性能测试
与 bytes.Index
实现的正逆向顺序搜索对比。
// main.go package main import ( "bytes" "fmt" "index/suffixarray" ) // 正向顺序搜索。 func bytesIndex(data, sep []byte) []int { ret := make([]int, 0, 300) pos, length := 0, len(sep) for { n := bytes.Index(data, sep) if n < 0 { break } ret = append(ret, pos+n) data = data[n+length:] pos += (n + length) } return ret } // 逆向顺序搜索。 func bytesLastIndex(data, sep []byte) []int { ret := make([]int, 0, 300) for { n := bytes.LastIndex(data, sep) if n < 0 { break } ret = append(ret, n) data = data[:n] } return ret } func main() { data := []byte{2, 1, 2, 3, 2, 1, 2, 4, 4, 2, 1} sep := []byte{2, 1} fmt.Println(bytesIndex(data, sep)) fmt.Println(bytesLastIndex(data, sep)) fmt.Println(suffixarray.New(data).Lookup(sep, -1)) } /* [0 4 9] [9 4 0] [9 0 4] */
用一个相对长的源码文件做测试样本数据。
// main_test.go package main import ( "io" "testing" "os" "regexp" "index/suffixarray" ) var ( data, sep []byte regx *regexp.Regexp index *suffixarray.Index ) func init() { f, _ := os.Open("/usr/local/go/src/runtime/malloc.go") data, _ = io.ReadAll(f) sep = []byte("func") regx, _ = regexp.Compile("func") index = suffixarray.New(data) } // ------------------------------------------ func BenchmarkLookup(b *testing.B) { for i := 0; i < b.N; i++ { _ = index.Lookup(sep, -1) } } func BenchmarkFindAllIndex(b *testing.B) { for i := 0; i < b.N; i++ { _ = index.FindAllIndex(regx, -1) } } func BenchmarkBytesIndex(b *testing.B) { for i := 0; i < b.N; i++ { _ = bytesIndex(data, sep) } } func BenchmarkBytesLastIndex(b *testing.B) { for i := 0; i < b.N; i++ { _ = bytesLastIndex(data, sep) } }
从结果看, bytes.LastIndex
最慢, suffixarray.Lookup
最快。
付出的代价是,构建后缀数组消耗更多内存。(memprofile)
$ go test -run None -bench . -benchmem cpu: Intel(R) Core(TM) i5-5257U CPU @ 2.70GHz BenchmarkLookup-2 1900341 588 ns/op 288 B/op 1 allocs/op BenchmarkFindAllIndex-2 481262 2562 ns/op 1784 B/op 4 allocs/op BenchmarkBytesIndex-2 65858 17841 ns/op 2688 B/op 1 allocs/op BenchmarkBytesLastIndex-2 10000 106121 ns/op 2688 B/op 1 allocs/op PASS
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论