支持中文的基于词为基本粒度的前缀树(prefix trie)实现

Trie树,也叫字典树、前缀树。可用于”predictive text”和”autocompletion”,亦可用于统计词频(边插入Trie树边更新或添加词频)。

计算机科学中,trie,又称前缀树字典树,是一种有序,用于保存关联数组,其中的键通常是字符串。与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定。一个节点的所有子孙都有相同的前缀,也就是这个节点对应的字符串,而根节点对应空字符串。一般情况下,不是所有的节点都有对应的值,只有叶子节点和部分内部节点所对应的键才有相关的值。

Trie 这个术语来自于 retrieval。根据词源学,trie 的发明者 Edward Fredkin 把它读作 英语发音:/?tri?/ "tree"。[1][2] 但是,其他作者把它读作 英语发音:/?tra?/ "try"。[1][2][3]

在图示中,键标注在节点中,值标注在节点之下。每一个完整的英文单词对应一个特定的整数。Trie 可以看作是一个确定有限状态自动机,尽管边上的符号一般是隐含在分支的顺序中的。

键不需要被显式地保存在节点中。图示中标注出完整的单词,只是为了演示 trie 的原理。

trie 中的键通常是字符串,但也可以是其它的结构。trie 的算法可以很容易地修改为处理其它结构的有序序列,比如一串数字或者形状的排列。比如,bitwise trie 中的键是一串位元,可以用于表示整数或者内存地址。

参考资料:http://zh.wikipedia.org/wiki/Trie

  1 #!/usr/bin/python
  2 # -*- coding:utf-8 -*-
  3 # * trie, prefix tree
  4 # * author: [email protected]
  5 import sys
  6 reload(sys)
  7 sys.setdefaultencoding("utf-8")
  8
  9 class Node:
 10   def __init__(self):
 11     self.value = None
 12     self.children = {}
 13
 14 class Trie:
 15   def __init__(self):
 16     self.root = Node()
 17
 18   def insert(self, key, value = None, sep = ‘ ‘):  # key is a word sequence separated by ‘sep‘
 19     elements = key.split(sep)
 20     node = self.root
 21     for e in elements:
 22       if not e: continue
 23       if e not in node.children:
 24         child = Node()
 25         node.children[e] = child
 26         node = child
 27       else:
 28         node = node.children[e]
 29     node.value = value
 30
 31   def search(self, key, default = None, sep = ‘ ‘):
 32     elements = key.split(sep)
 33     node = self.root
 34     for e in elements:
 35       if e not in node.children:
 36         return default
 37       node = node.children[e]
 38     return node.value
 39
 40   def delete(self, key, sep = ‘ ‘):
 41     elements = key.split(sep)
 42     self.__delete(elements)
 43
 44   def __delete(self, elements, node = None, i = 0):
 45     node = node if node else self.root
 46     e = elements[i]
 47     if e in node.children:
 48       child_node = node.children[e]
 49       if len(elements) == (i+1):
 50         return node.children.pop(e) if len(child_node.children)==0 else False
 51       elif self.__delete(elements, child_node, i+1):
 52         return node.children.pop(e) if (len(child_node.children)==0 and not child_node.value) else False
 53     return False
 54
 55   def longest_prefix(self, key, sep = ‘ ‘):
 56     elements = key.split(sep)
 57     results = []
 58     node = self.root
 59     for e in elements:
 60       if e not in node.children:
 61         return sep.join(results)
 62       results.append(e)
 63       node = node.children[e]
 64     return sep.join(results)
 65
 66   def longest_prefix_value(self, key, default = None, sep = ‘ ‘):
 67     elements = key.split(sep)
 68     value = default
 69     node = self.root
 70     for e in elements:
 71       if e not in node.children:
 72         return value
 73       node = node.children[e]
 74       value = node.value
 75     return value if value else default
 76
 77   def longest_prefix_item(self, key, sep = ‘ ‘):
 78     elements = key.split(sep)
 79     node = self.root
 80     value = node.value
 81     results = []
 82     for e in elements:
 83       if e not in node.children:
 84         return (sep.join(results), value)
 85       results.append(e)
 86       node = node.children[e]
 87       value = node.value
 88     return (sep.join(results), value)
 89
 90   def __collect_items(self, node, path, results, sep):
 91     if node.value:
 92       results.append((sep.join(path), node.value))
 93     for k, v in node.children.iteritems():
 94       path.append(k)
 95       self.__collect_items(v, path, results, sep)
 96       path.pop()
 97     return results
 98
 99   def items(self, prefix, sep = ‘ ‘):
100     elements = prefix.split(sep)
101     node = self.root
102     for e in elements:
103       if e not in node.children:
104         return []
105       node = node.children[e]
106     results = []
107     path = [prefix]
108     self.__collect_items(node, path, results, sep)
109     return results
110
111   def keys(self, prefix, sep = ‘ ‘):
112     items = self.items(prefix, sep)
113     return [key for key,value in items]
114
115 if __name__ == ‘__main__‘:
116   trie = Trie()
117   trie.insert(‘happy 站台‘, 1)
118   trie.insert(‘happy 站台 美食 购物 广场‘, 2)
119   trie.insert(‘sm‘, 1)
120   trie.insert(‘sm 国际 广场‘, 2)
121   trie.insert(‘sm 城市广场‘, 3)
122   trie.insert(‘sm 广场‘, 4)
123   trie.insert(‘sm 新生活 广场‘, 5)
124   trie.insert(‘sm 购物 广场‘, 6)
125   trie.insert(‘soho 尚都‘, 3)
126
127   print trie.search(‘sm‘)
128   print trie.search(‘sm 广场‘)
129   print trie.search(‘sm 新东方广场‘)
130   print trie.search(‘神马‘)
131   print trie.search(‘happy 站台‘)
132   print trie.search(‘happy 站台 美食 购物 广场‘)
133   print trie.longest_prefix(‘soho 广场‘)
134   print trie.longest_prefix(‘soho 尚都 广场‘)
135   print trie.longest_prefix_value(‘soho 尚都 广场‘)
136   print trie.longest_prefix_value(‘xx 尚都 广场‘, 90)
137   print trie.longest_prefix_item(‘soho 尚都 广场‘)
138
139   print ‘============== keys =================‘
140   print ‘prefix "sm": ‘, ‘ | ‘.join(trie.keys(‘sm‘))
141   print ‘============== items =================‘
142   print ‘prefix "sm": ‘, trie.items(‘sm‘)
143
144   print ‘================= delete =====================‘
145   trie.delete(‘sm 广场‘)
146   print trie.search(‘sm 广场‘)  

运行结果如下:

1
4
None
None
1
2
soho
soho 尚都
3
90
(‘soho \xe5\xb0\x9a\xe9\x83\xbd‘, 3)
============== keys =================
prefix "sm":  sm | sm 新生活 广场 | sm 城市广场 | sm 广场 | sm 购物 广场 | sm 国际 广场
============== items =================
prefix "sm":  [(‘sm‘, 1), (‘sm \xe6\x96\xb0\xe7\x94\x9f\xe6\xb4\xbb \xe5\xb9\xbf\xe5\x9c\xba‘, 5), (‘sm \xe5\x9f\x8e\xe5\xb8\x82\xe5\xb9\xbf\xe5\x9c\xba‘, 3), (‘sm \xe5\xb9\xbf\xe5\x9c\xba‘, 4), (‘sm \xe8\xb4\xad\xe7\x89\xa9 \xe5\xb9\xbf\xe5\x9c\xba‘, 6), (‘sm \xe5\x9b\xbd\xe9\x99\x85 \xe5\xb9\xbf\xe5\x9c\xba‘, 2)]
================= delete =====================
None

  

时间: 2024-10-14 18:34:46

支持中文的基于词为基本粒度的前缀树(prefix trie)实现的相关文章

支持中文的基于词为基本粒度的前缀树(prefix trie)python实现

Trie树,也叫字典树.前缀树.可用于"predictive text"和"autocompletion".亦可用于统计词频(边插入Trie树边更新或加入词频). 在计算机科学中.trie,又称前缀树或字典树.是一种有序树,用于保存关联数组,当中的键一般是字符串.与二叉查找树不同.键不是直接保存在节点中,而是由节点在树中的位置决定.一个节点的全部子孙都有同样的前缀,也就是这个节点相应的字符串,而根节点相应空字符串. 普通情况下,不是全部的节点都有相应的值,仅仅有叶子

Sphinx在windows下安装使用(支持中文全文检索)

前段时间听同事谈起过,公司内部的一个搜索功能用的就是Sphinx,但一直没时间去整一下,今天刚好有点时间,那么就折腾一次吧.一般在linux上比较多,今天就在windows下安装于调试一下吧. 前言: 一.关于Sphinx Sphinx 是一个在GPLv2 下发布的一个全文检索引擎,商业授权(例如, 嵌入到其他程序中)需要联系作者(Sphinxsearch.com)以获得商业授权.一般而言,Sphinx是一个独立的搜索引擎,意图为其他应用提供高速.低空间占用.高结果相关度的全文搜索功能.Sphi

helm-mode打开文件支持中文搜索

.title { text-align: center; margin-bottom: .2em } .subtitle { text-align: center; font-size: medium; font-weight: bold; margin-top: 0 } .todo { font-family: monospace; color: red } .done { font-family: monospace; color: green } .priority { font-fami

在Mac下安装使用支持中文的LaTeX(二)

在上一篇文章中,我们提到了如何在Mac OS X(笔者所使用的是10.10,Hackintosh)下面安装并使用支持中文的MacTeX.事实上,MacTeX在安装好之后就已经默认支持多国语言,比如日语等(由于pTeX的存在,排版日文可能要更方便一些). 实际上,LaTeX是基于TeX的排版系统.TeX在刚刚诞生时,尽管它可以排版出非常漂亮的文章,但是其代码也十分复杂,使得很多人难以掌握.因此,LaTeX诞生了.它以TeX为基础,通过宏包的方式大大简化了代码.在这篇文章中,我们仅简单地说明上一篇文

jQuery.qrcode.js客户端生成二维码,支持中文并且可以生成LOGO

描述: jquery.qrcode.js 是一个能够在客户端生成矩阵二维码QRCode 的jquery插件 ,使用它可以很方便的在页面上生成二维条码.此插件是能够独立使用的,体积也比较                 小,使用gzip压缩后才不到4kb.因为它是直接在客户端生成的条码, 所以不会有图片下载的过程,能够实现快速生成.它是基于一个多语言的类库封装的,也不依赖于其他额外的服务. 好处:使用jquery-qrcode的好处,不需要在服务器端生成多余的二维码图片,二维码直接通过JavaSc

基线系统需要受到更多关注:基于词向量的简单模型

最近阅读了<Baseline Needs More Love: On Simple Word-Embedding-Based Models and Associated Pooling Mechanisms>这篇论文[1],该工作来自杜克大学,发表在ACL 2018上.论文详细比较了直接在词向量上进行池化的简单模型和主流神经网络模型(例如CNN和RNN)在NLP多个任务上的效果.实验结果表明,在很多任务上简单的词向量模型和神经网络模型(CNN和LSTM)的效果相当,有些任务甚至简单模型更好.下

VSCode配置LaTeX Workstation以支持中文

前言: 一直以来都羡慕着LaTeX的强大排版功能,这次在为美赛做准备时,发现VSCode也可以配置LaTeX(不得不说微软还是很牛逼的),所以有了这篇小文章. 系统环境配置 基于Windows 10 安装TexLive 官网下载地址安装过程会比较久,主要原因是要下载镜像.(可能需要配置系统环境变量) 安装VSCode 官网VSCode下载地址.VSCode自从面世以来,备受关注,我个人觉得也很好用,这是 安装LaTeX WorkStation 打开VSCode,点击左侧面板上第五个叫做[扩展]的

Azure SQL Database (22) Azure SQL Database支持中文值

<Windows Azure Platform 系列文章目录> 在笔者之前的文章里,已经介绍了如何使Azure SQL Database支持中文: SQL Azure(七) 在SQL Azure Database中执行的T-SQL 其中的关键步骤是: 1.使用默认的字符集:SQL_LATIN1_GENERAL_CP1_CI_AS 2.显示中文的字段列,类型必须为NVARCHAR 3.插入中文字符时,在字符串前面加上一个大写字母N 但是在有些时候,把所有的T-SQL语句在字符串前面加上一个大写字

让linux(centos)支持中文文件和文件夹

一.让linux支持中文 1.将Linux的env设置了LANG=en_US.UTF-8: 2.本地的Shell客户端编码也设置成UTF-8,这样让在windows上传到linux的文件或者目录不会出现乱码: 3.重要:如果用SecureFXPortable上传时需要需要手工编辑SecrueFX的这个Session的配置文件才行(找到session文件夹) 在SecureFx中选择Options->Global Options菜单,在打开的Global Options的对话框中选择General