Trie Tree算法概述及Python实现

Trie Tree广泛的使用与分词和检索算法中,在实现聊天机器人时,常用来作为高级数据的存储,因为其存储和搜索效率较高。本文给出数据定义和工作原理,python的实现。

数据结构

class Node():
	static = 0
	def __init__(self):
		self.fail = None
		self.next = [None]*KIND
		self.end = False
		self.word = None
		Node.static += 1

分词原理

(1) 从根结点开始一次搜索,比如搜索【北京】;
(2) 取得要查找关键词的第一个字符【北】,并根据该字符选择对应的子树并转到该子树继续进行检索;
(3) 在相应的子树上,取得要查找关键词的第二个字符【京】,并进一步选择对应的子树进行检索。
(4) 迭代过程……
(5) 在直到判断树节点的isEnd节点为true则查找结束(最小匹配原则),然后发现【京】isEnd=true,则结束查找。

如果是最大匹配原则,遇到isEnd前也会看其他叶子中,是否可以匹配。

方法

  • insert
    添加节点

  • find
    查找字符串

  • delete
    删除节点

使用 Python 实现

#coding=utf-8
import sys
 
KIND = 16
#BASE = ord('a')
 
class Node():
	static = 0
	def __init__(self):
		self.fail = None
		self.next = [None]*KIND
		self.end = False
		self.word = None
		Node.static += 1
 
class AcAutomation():
	def __init__(self):
		self.root = Node()
		self.queue = []
		
	def getIndex(self,char):
		return ord(char)# - BASE
	
	def insert(self, string):
		p = self.root
		for char in string:
			index = self.getIndex(char)
			if p.next[index] == None:
				p.next[index] = Node()
			p = p.next[index]
		p.end = True
		p.word = string
		
	def build_automation(self):
		self.root.fail = None
		self.queue.append(self.root)
		while len(self.queue)!=0:
			parent = self.queue[0]
			self.queue.pop(0)
			for i,child in enumerate(parent.next):
				if child == None: continue
				if parent == self.root:
					child.fail = self.root
				else:
					failp = parent.fail
					while failp != None:
						if failp.next[i] != None:
							child.fail = failp.next[i]
							break
						failp = failp.fail
					if failp==None: child.fail=self.root
				self.queue.append(child)
				
	def matchOne(self, string):
		p = self.root
		for char in string:
			index = self.getIndex(char)
			while p.next[index]==None and p!=self.root: p=p.fail
			if p.next[index]==None:p=self.root
			else: p=p.next[index]
			if p.end:return True,p.word
		return False,None
 
	def matchAll(self, string):
		matches = []
		p = self.root
		for char in string:
			index = self.getIndex(char)
			while p.next[index]==None and p!=self.root: p=p.fail
			if p.next[index]==None:p=self.root
			else: p=p.next[index]
			if p.end:matches.append(p.word)
		if len(matches) > 0:return True,matches
		else:return False,None

class UnicodeAcAutomation():
	def __init__(self,encoding='utf-8'):
		self.ac = AcAutomation()
		self.encoding = encoding
		
	def getAcString(self,string):
		string = bytearray(string.encode(self.encoding))
		ac_string = ''
		for byte in string:
			ac_string += chr(byte%16)
			ac_string += chr(byte/16)
		#print ac_string
		return ac_string
	
	def insert(self,string):
		if type(string) != unicode:
			raise Exception('UnicodeAcAutomation:: insert type not unicode')
		ac_string = self.getAcString(string)
		self.ac.insert(ac_string)
 
	def build_automation(self):
		self.ac.build_automation()
	
	def matchOne(self,string):
		if type(string) != unicode:
			raise Exception('UnicodeAcAutomation:: insert type not unicode')
		ac_string = self.getAcString(string)
		retcode,ret = self.ac.matchOne(ac_string)
		if ret!=None:
			s = ''
			for i in range(len(ret)/2):
				s += chr(ord(ret[2*i])+ord(ret[2*i+1])*16)
			ret = s.decode('utf-8')
		return retcode, ret
	
	def matchAll(self,string):
		if type(string) != unicode:
			raise Exception('UnicodeAcAutomation:: insert type not unicode')
		ac_string = self.getAcString(string)
		retcode,ret = self.ac.matchOne(ac_string)
                print(1)
                print(ret)
                print(2)
		results = []
		if ret!=None and len(ret) > 0:
			for r in ret:
				s = ''
				for i in range(len(r)/2):
					s += chr(ord(r[2*i])+ord(r[2*i+1])*16)
				results.append(s.decode('utf-8'))
		return retcode, results

if __name__ == '__main__':
    lines = ["北京", "上海", "杭州", "大连"]
    test = UnicodeAcAutomation()
    for line in lines:
	test.insert(unicode(line, "utf8"))
	test.build_automation()
    bar = "北京" + "在哪里"
    code, rets = test.matchAll(unicode(bar, "utf8"))
    print("code: %s" % code)
    print("rets: %s" % rets)

扩展

还可以使用TrieTree存储更多信息,比如每个key绑定一个value,根据key进行查询,返回value。

参考

Trie Tree 实现中文分词器
基于Trie Tree构建的ForestDB

Hai Liang Wang 深度学习 算法 自然语言处理
Chatopera 联合创始人 & CEO,运营聊天机器人平台 https://bot.chatopera.com,让聊天机器人上线!2012年开始从事业务流程云,业务流程引擎开发,2015年开始探索聊天机器人的商业应用,实现基于自然语言交互的流程引擎、语音识别、自然语言理解,2018年出版《智能问答与深度学习》一书。
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值