支持中文的基于词为基本粒度的前缀树(prefix trie)python实现
Trie树,也叫字典树、前缀树。可用于”predictive text”和”autocompletion”。亦可用于统计词频(边插入Trie树边更新或加入词频)。
在计算机科学中。trie,又称前缀树或字典树。是一种有序树,用于保存关联数组,当中的键一般是字符串。与二叉查找树不同。键不是直接保存在节点中,而是由节点在树中的位置决定。一个节点的全部子孙都有同样的前缀,也就是这个节点相应的字符串,而根节点相应空字符串。
普通情况下,不是全部的节点都有相应的值,仅仅有叶子节点和部分内部节点所相应的键才有相关的值。
參考资料:http://zh.wikipedia.org/wiki/Trie
#!/usr/bin/python
# -*- coding:utf-8 -*-
# * trie, prefix tree, can be used as a dict
# * author: yangxudongsuda@gmail.com
import sys
reload(sys)
sys.setdefaultencoding("utf-8") # Singleton sentinel - works with pickling
class NULL(object):
pass class Node:
def __init__(self, value = NULL):
self.value = value
self.children = {} class Trie(object):
def __init__(self):
self.root = Node() def insert(self, key, value = None, sep = ' '): # key is a word sequence separated by 'sep'
elements = key if isinstance(key, list) else key.split(sep)
node = self.root
for e in elements:
if not e: continue
if e not in node.children:
child = Node()
node.children[e] = child
node = child
else:
node = node.children[e]
node.value = value def get(self, key, default = None, sep = ' '):
elements = key if isinstance(key, list) else key.split(sep)
node = self.root
for e in elements:
if e not in node.children:
return default
node = node.children[e]
return default if node.value is NULL else node.value def delete(self, key, sep = ' '):
elements = key if isinstance(key, list) else key.split(sep)
return self.__delete(elements) def __delete(self, elements, node = None, i = 0):
node = node if node else self.root
e = elements[i]
if e in node.children:
child_node = node.children[e]
if len(elements) == (i+1):
if child_node.value is NULL: return False # not in dict
if len(child_node.children) == 0:
node.children.pop(e)
else:
child_node.value = NULL
return True
elif self.__delete(elements, child_node, i+1):
if len(child_node.children) == 0:
return node.children.pop(e)
return True
return False def shortest_prefix(self, key, default = NULL, sep = ' '):
elements = key if isinstance(key, list) else key.split(sep)
results = []
node = self.root
value = node.value
for e in elements:
if e in node.children:
results.append(e)
node = node.children[e]
value = node.value
if value is not NULL:
return sep.join(results)
else:
break
if value is NULL:
if default is not NULL:
return default
else:
raise Exception("no item matches any prefix of the given key!")
return sep.join(results) def longest_prefix(self, key, default = NULL, sep = ' '):
elements = key if isinstance(key, list) else key.split(sep)
results = []
node = self.root
value = node.value
for e in elements:
if e not in node.children:
if value is not NULL:
return sep.join(results)
elif default is not NULL:
return default
else:
raise Exception("no item matches any prefix of the given key!")
results.append(e)
node = node.children[e]
value = node.value
if value is NULL:
if default is not NULL:
return default
else:
raise Exception("no item matches any prefix of the given key!")
return sep.join(results) def longest_prefix_value(self, key, default = NULL, sep = ' '):
elements = key if isinstance(key, list) else key.split(sep)
node = self.root
value = node.value
for e in elements:
if e not in node.children:
if value is not NULL:
return value
elif default is not NULL:
return default
else:
raise Exception("no item matches any prefix of the given key!")
node = node.children[e]
value = node.value
if value is not NULL:
return value
if default is not NULL:
return default
raise Exception("no item matches any prefix of the given key!") def longest_prefix_item(self, key, default = NULL, sep = ' '):
elements = key if isinstance(key, list) else key.split(sep)
node = self.root
value = node.value
results = []
for e in elements:
if e not in node.children:
if value is not NULL:
return (sep.join(results), value)
elif default is not NULL:
return default
else:
raise Exception("no item matches any prefix of the given key!")
results.append(e)
node = node.children[e]
value = node.value
if value is not NULL:
return (sep.join(results), value)
if default is not NULL:
return (sep.join(results), default)
raise Exception("no item matches any prefix of the given key!") def __collect_items(self, node, path, results, sep):
if node.value is not NULL:
results.append((sep.join(path), node.value))
for k, v in node.children.iteritems():
path.append(k)
self.__collect_items(v, path, results, sep)
path.pop()
return results def items(self, prefix, sep = ' '):
elements = prefix if isinstance(prefix, list) else prefix.split(sep)
node = self.root
for e in elements:
if e not in node.children:
return []
node = node.children[e]
results = []
path = [prefix]
self.__collect_items(node, path, results, sep)
return results def keys(self, prefix, sep = ' '):
items = self.items(prefix, sep)
return [key for key,value in items] if __name__ == '__main__':
trie = Trie()
trie.insert('happy 站台', 1)
trie.insert('happy 站台 xx', 10)
trie.insert('happy 站台 xx yy', 11)
trie.insert('happy 站台 美食 购物 广场', 2)
trie.insert('sm')
trie.insert('sm 国际', 22)
trie.insert('sm 国际 广场', 2)
trie.insert('sm 城市广场', 3)
trie.insert('sm 广场', 4)
trie.insert('sm 新生活 广场', 5)
trie.insert('sm 购物 广场', 6)
trie.insert('soho 尚都', 3) print trie.get('sm')
print trie.longest_prefix([], default="empty list")
print trie.longest_prefix('sm')
print trie.shortest_prefix('happy 站台')
print trie.shortest_prefix('happy 站台 xx')
print trie.shortest_prefix('sm')
print trie.longest_prefix('sm xx', sep = '&', default = None)
print 'sm 广场 --> ', trie.get('sm 广场')
print trie.get('sm 广场'.split(' '))
print trie.get('神马')
print trie.get('happy 站台')
print trie.get('happy 站台 美食 购物 广场')
print trie.longest_prefix('soho 广场', 'default')
print trie.longest_prefix('soho 尚都 广场')
print trie.longest_prefix_value('soho 尚都 广场')
print trie.longest_prefix_value('xx 尚都 广场', 90)
print trie.longest_prefix_value('xx 尚都 广场', 'no prefix')
print trie.longest_prefix_item('soho 尚都 广场') print '============== keys ================='
print 'prefix "sm": ', ' | '.join(trie.keys('sm'))
print '============== items ================='
print 'prefix "sm": ', trie.items('sm') print '================= delete ====================='
print trie.delete('sm 广场')
print trie.get('sm 广场')
print trie.delete('sm 国际')
print trie.get('sm 国际')
print trie.delete('sm xx')
print trie.delete('xx') print '====== no item matches any prefix of given key ========'
print trie.longest_prefix_value('happy')
print trie.longest_prefix_value('soho xx')
执行结果:
None
empty list
sm
happy 站台
happy 站台
sm
None
sm 广场 --> 4
4
None
1
2
default
soho 尚都
3
90
no prefix
('soho \xe5\xb0\x9a\xe9\x83\xbd', 3)
============== keys =================
prefix "sm": sm | sm 新生活 广场 | sm 城市广场 | sm 广场 | sm 购物 广场 | sm 国际 | sm 国际 广场
============== items =================
prefix "sm": [('sm', None), ('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', 22), ('sm \xe5\x9b\xbd\xe9\x99\x85 \xe5\xb9\xbf\xe5\x9c\xba', 2)]
================= delete =====================
True
None
True
None
False
False
====== no item matches any prefix of given key ========
Traceback (most recent call last):
File "./word_based_trie.py", line 225, in <module>
print trie.longest_prefix_value('happy')
File "./word_based_trie.py", line 128, in longest_prefix_value
raise Exception("no item matches any prefix of the given key!")
Exception: no item matches any prefix of the given key!
支持中文的基于词为基本粒度的前缀树(prefix trie)python实现的更多相关文章
- 基于bert的命名实体识别,pytorch实现,支持中文/英文【源学计划】
声明:为了帮助初学者快速入门和上手,开始源学计划,即通过源代码进行学习.该计划收取少量费用,提供有质量保证的源码,以及详细的使用说明. 第一个项目是基于bert的命名实体识别(name entity ...
- 基于myscript.js的web手写板(支持中文识别)
网上的手写板模板不少,但是支持中文识别的却不多,而且基本上都收费的,毕竟别人的中文库凭什么免费提供给你(说好的开源呢?说好的开源呢? ←_←) 好了,进入主题,myscript.js,在官网其实我并没 ...
- Sphinx在windows下安装使用[支持中文全文检索]
原文地址:http://www.fuchaoqun.com/2008/11/sphinx-on-windows-xp/ 前 一阵子尝试使用了一下Sphinx,一个能够被各种语言(PHP/Python/ ...
- jQuery.qrcode.js客户端生成二维码,支持中文并且可以生成LOGO
描述: jquery.qrcode.js 是一个能够在客户端生成矩阵二维码QRCode 的jquery插件 ,使用它可以很方便的在页面上生成二维条码.此插件是能够独立使用的,体积也比较 ...
- flying-saucer + iText + Freemarker实现pdf的导出, 支持中文、css以及图片
前言 项目中有个需求,需要将合同内容导出成pdf.上网查阅到了 iText , iText 是一个生成PDF文档的开源Java库,能够动态的从XML或者数据库生成PDF,同时还可以对文档进行加密,权限 ...
- PHP生成PDF完美支持中文,解决TCPDF乱码
PHP生成PDF完美支持中文,解决TCPDF乱码 2011-09-26 09:04 418人阅读 评论(0) 收藏 举报 phpfontsheaderttfxhtml文档 PHP生成PDF完美支持中文 ...
- helm-mode打开文件支持中文搜索
helm-mode打开文件支持中文搜索 */--> code {color: #FF0000} pre.src {background-color: #002b36; color: #83949 ...
- 构建支持中文字体的moviepy镜像
首先是系统的环境问题. linux 安装 moviepy需要很多依赖,安装起来费神费力.配置起来也非常麻烦,最简单的办法是直接使用他人构建好的镜像文件. 再就是字体显示问题. 镜像中的imagmagi ...
- 支持中文!秒建 wiki 知识库的开源项目,构建私人知识网络
不知道有没有人和我一样,觉得自建的东西是互联网上的"自留地".私人空间,有一种自己的一亩三分地随心所欲的痛快. 比如自建的博客想写什么随笔就写什么,不用取悦读者可以自娱自乐:再比如 ...
随机推荐
- PCB 线路板人生
由此开端,增加PCB人生分类栏,后续在此分享PCB 非工作方面所思所想,由于文笔不好,请指正.
- Oracle占用内存过高解决办法
1.cmd sqlplus system账户登录 2.show parameter sga; --显示内存分配情况 3.alter system set sga_max_size=200m scope ...
- 【DP】书的复制
原题链接__戳我噢 [思路] (区间)DP F[I][J]表示前i本书分给j个人用的最短时间 由于每一次j的状态由比j小的状态得出,所以要先枚举j,然后枚举i,接着枚举上一次抄书的人是谁 我觉得,难点 ...
- 记录一个MySQL的问题
昨天做asp.net mvc程序,用mysql.data.entity.ef6做数据连接. 程序都是正常的,但就是提交数据的时候总是提示 Specified key was too long; max ...
- 使用TortoiseSVN碰到的几个问题(2)-冲突解决, 图标重载
8)解决冲突 冲突分为两种:文件冲突---当两名(或更多)开发人员修改了同一个文件中相邻或相同的行时就会发生文件冲突.下面的属性冲突应该也属于文件冲突. 树冲突---当一名开发人员移动.重命名.删除一 ...
- SecureCRT连接Ubuntu报The remote system refused the connection.解决方案
使用SecureCRT连接到远程Ubuntu,连接失败报The remote system refused the connection. 进入Ubuntu系统,终端中敲入以下命令: ps -ef|g ...
- C++对象的内存模型
1. 普通对象模型 对象是如何在内存中布局的? 成员 存放位置 访问范围 非静态数据成员 每一个对象体内 为该对象专有 静态数据成员 程序的静态存储区内,只有一份实体 为该类所有对象共享 成员函数(静 ...
- 【转】虚拟化(二):虚拟化及vmware workstation产品使用
vmware workstation的最新版本是10.0.2.相信大家也都使用过,其中的简单的虚拟机的创建,删除等,都很简单,这里就不再详细说明了,下面我将简单介绍下vmware workstatio ...
- loadrunner录制不了浏览器
Loadrunner11.0启动WebTours之总结1 第一次安装LR11时,安装安组件后没有对电脑进行重启,直接安装的LR112 安装完毕LR后,录制脚本时发现不能启动IE11.百度发现LR支持I ...
- C#第二节课
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...