golang高效Trie树数据结构实现插件库trie的使用

Golang高效Trie树数据结构实现插件库trie的使用

Trie简介

Trie是一种用于极快速前缀/模糊字符串搜索的数据结构和相关算法。

GoDoc

使用示例

创建Trie

t := trie.New()

添加键值

// Add方法可以接收元信息,这些信息可以与键一起存储
// 即你可以存储任何你想与该键关联的信息
t.Add("foobar", 1)

查找键

node, ok := t.Find("foobar")
meta := node.Meta()
// 使用meta.(type)来处理元数据

移除键

t.Remove("foobar")

前缀搜索

t.PrefixSearch("foo")

快速测试有效前缀

t.HasKeysWithPrefix("foo")

模糊搜索

t.FuzzySearch("fb")

完整示例Demo

package main

import (
	"fmt"
	"github.com/derekparker/trie"
)

func main() {
	// 创建新的Trie树
	t := trie.New()
	
	// 添加键值对
	t.Add("golang", "Go语言")
	t.Add("python", "Python语言")
	t.Add("java", "Java语言")
	t.Add("javascript", "JavaScript语言")
	
	// 查找特定键
	if node, ok := t.Find("golang"); ok {
		fmt.Println("找到golang:", node.Meta()) // 输出: 找到golang: Go语言
	}
	
	// 前缀搜索
	fmt.Println("前缀'jav'的搜索结果:", t.PrefixSearch("jav")) 
	// 输出: 前缀'jav'的搜索结果: [java javascript]
	
	// 模糊搜索
	fmt.Println("模糊搜索'pytn'的结果:", t.FuzzySearch("pytn"))
	// 输出: 模糊搜索'pytn'的结果: [python]
	
	// 检查前缀是否存在
	fmt.Println("是否存在'go'前缀:", t.HasKeysWithPrefix("go")) 
	// 输出: 是否存在'go'前缀: true
	
	// 移除键
	t.Remove("python")
	fmt.Println("移除python后前缀'pyt'的搜索结果:", t.PrefixSearch("pyt"))
	// 输出: 移除python后前缀'pyt'的搜索结果: []
}

贡献

克隆此仓库并运行测试:

go test

创建一个特性分支,编写你的测试和代码,然后提交拉取请求。

许可证

MIT


更多关于golang高效Trie树数据结构实现插件库trie的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang高效Trie树数据结构实现插件库trie的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang高效Trie树实现及使用指南

Trie树(前缀树或字典树)是一种高效的字符串检索数据结构,特别适合实现自动补全、拼写检查、IP路由等功能。下面我将介绍如何在Go中高效实现和使用Trie树。

标准Trie树实现

基础实现代码

package main

import (
	"fmt"
)

type TrieNode struct {
	children map[rune]*TrieNode
	isEnd    bool
}

type Trie struct {
	root *TrieNode
}

func NewTrie() *Trie {
	return &Trie{root: &TrieNode{children: make(map[rune]*TrieNode)}}
}

// Insert 插入一个单词到Trie树中
func (t *Trie) Insert(word string) {
	node := t.root
	for _, ch := range word {
		if _, ok := node.children[ch]; !ok {
			node.children[ch] = &TrieNode{children: make(map[rune]*TrieNode)}
		}
		node = node.children[ch]
	}
	node.isEnd = true
}

// Search 查找单词是否存在于Trie树中
func (t *Trie) Search(word string) bool {
	node := t.root
	for _, ch := range word {
		if _, ok := node.children[ch]; !ok {
			return false
		}
		node = node.children[ch]
	}
	return node.isEnd
}

// StartsWith 检查是否有单词以给定前缀开头
func (t *Trie) StartsWith(prefix string) bool {
	node := t.root
	for _, ch := range prefix {
		if _, ok := node.children[ch]; !ok {
			return false
		}
		node = node.children[ch]
	}
	return true
}

func main() {
	trie := NewTrie()
	trie.Insert("apple")
	fmt.Println(trie.Search("apple"))   // true
	fmt.Println(trie.Search("app"))     // false
	fmt.Println(trie.StartsWith("app")) // true
	trie.Insert("app")
	fmt.Println(trie.Search("app"))     // true
}

高效Trie树插件库

对于生产环境,推荐使用成熟的Trie库,如:

  1. github.com/derekparker/trie
  2. github.com/Workiva/go-datastructures/trie/ctrie

使用示例:derekparker/trie

package main

import (
	"fmt"
	"github.com/derekparker/trie"
)

func main() {
	t := trie.New()
	
	// 插入键值对
	t.Add("apple", 1)
	t.Add("app", 2)
	t.Add("application", 3)
	t.Add("banana", 4)
	
	// 精确查找
	node, ok := t.Find("app")
	if ok {
		fmt.Println("Found:", node.Meta()) // 输出: 2
	}
	
	// 前缀查找
	nodes := t.PrefixSearch("app")
	for _, n := range nodes {
		fmt.Printf("%s: %v\n", n.Key(), n.Meta())
	}
	// 输出:
	// app: 2
	// apple: 1
	// application: 3
	
	// 删除键
	t.Remove("apple")
	
	// 遍历所有键
	t.Each(func(key string, value interface{}) bool {
		fmt.Println(key, value)
		return true // 返回false可提前终止遍历
	})
}

使用示例:Workiva的并发安全Trie (ctrie)

package main

import (
	"fmt"
	"github.com/Workiva/go-datastructures/trie/ctrie"
	"time"
)

func main() {
	c := ctrie.New(nil)
	
	// 插入
	c.Insert([]byte("apple"), 1)
	c.Insert([]byte("app"), 2)
	
	// 查找
	if val, ok := c.Lookup([]byte("app")); ok {
		fmt.Println("Found:", val) // 输出: 2
	}
	
	// 并发安全操作
	go func() {
		c.Insert([]byte("banana"), 3)
	}()
	
	go func() {
		c.Insert([]byte("orange"), 4)
	}()
	
	time.Sleep(100 * time.Millisecond)
	
	// 快照
	snapshot := c.Snapshot()
	
	// 遍历
	snapshot.Iterator(func(k []byte, v interface{}) bool {
		fmt.Println(string(k), v)
		return true
	})
}

性能优化技巧

  1. 压缩Trie:合并只有一个子节点的节点,减少内存使用
  2. 双数组Trie:使用两个数组代替指针,提高缓存命中率
  3. 并发安全:对于高并发场景,使用并发安全实现
  4. 内存池:重用节点对象减少GC压力

应用场景

  1. 自动补全:快速查找前缀匹配的所有单词
  2. 拼写检查:快速判断单词是否存在
  3. IP路由:最长前缀匹配
  4. 敏感词过滤:高效检测文本中的敏感词

选择哪种实现取决于具体需求:标准Trie适合简单场景,derekparker/trie功能丰富,Workiva的ctrie适合高并发环境。

希望这个指南能帮助你在Go项目中高效使用Trie数据结构!

回到顶部