数据结构与算法---字典树 | 青训营笔记

136 阅读2分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第4篇笔记。

抖音项目开发过程中,打算实现一个过滤敏感词的Filter组件,所用到的数据结构为字典树(trie)

  1. 字典树的简单介绍 字典树(又叫单词查找树、TrieTree),是一种树形结构,典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串)。主要思想是利用字符串的公共前缀来节约存储空间。很好地利用了串的公共前缀,节约了存储空间。 它是一种哈希树的变种,常用于,统计,排序,保存大量字符串(但不仅限于字符串),主要实现方法是利用串的公共前缀来减少查询时间,减少了不必要的比较,不仅节约了存储空间,而且检索的效率比哈希表要高。

字典树的建树过程很简单,使用公共前缀(下图即为一颗字典树) 74f94f8e122e5bec124ba26ddec1d607_Qu8z1f.png

在建好树后,过滤敏感词的过程即为在树上对文本内容进行字符串匹配的过程

  1. 具体实现(见项目:github.com/uccInf/TikT…
package utils

import (
	"TikTok/constdef"
	"fmt"
	"unicode/utf8"
)

var invalidWords = []string{"傻逼", "sb", "赌博", "弱智"}
var trie *Trie

type Trie struct {
	child map[rune]*Trie
	word  string
}

func NewTrie() *Trie {
	return &Trie{
		child: make(map[rune]*Trie),
		word:  "",
	}
}

func (trie *Trie) insert(word string) *Trie {
	cur := trie
	for _, v := range []rune(word) {
		if _, ok := cur.child[v]; !ok {
			t := NewTrie()
			cur.child[v] = t
		}
		cur = cur.child[v]
	}
	cur.word = word
	return trie
}

func (trie *Trie) FilterString(word string) string {
	cur := trie

	for i, v := range []rune(word) {
		if _, ok := cur.child[v]; ok {
			cur = cur.child[v]
			if cur.word != "" {
				word = replaceStr(word, constdef.Replace, i+1-utf8.RuneCountInString(cur.word), i)
				cur = trie 
			}
		} else {
			cur = trie
	}
	return word
}

func replaceStr(word, replace string, left, right int) string {
	str := ""
	for i, v := range []rune(word) {
		if i >= left && i <= right {
			str = str + replace
		} else {
			str += string(v)
		}
	}
	return str
}

func init() {
	trie = NewTrie()
	for i := 0; i < len(invalidWords); i++ {
		trie.insert(invalidWords[i])
	}
}

func GetTrie() *Trie {
	return trie
}

测试代码:

package main

import (
	"TikTok/utils"
	"fmt"
)

func main() {
	var t = utils.GetTrie()
	fmt.Println(t.FilterString("傻逼,sb, sdf, 尼玛 ,哈哈哈哈哈"))
}