使用python代码实现三叉搜索树高效率”自动输入提示”功能

标签: python 代码 三叉 | 发表时间:2011-10-20 22:51 | 作者:(author unknown) est
出处:http://simple-is-better.com/

最近项目中需要通过全拼音和简写拼音实现输入自动提示结果功能,查了一些资料发现三叉搜索树无论是在时间还是空间上都比较优秀。
三叉搜索树是trie树的演化版,除去了指针,这样在空间上节省不少,每个节点基本分为三个方向:左、中、右,当字符小于当前节点则存放左边,大于则存放右边,等于则存放中间。
具体实现原理可参考:http://igoro.com/archive/efficient-auto-complete-with-a-ternary-search-tree/

假如我们存入”AB”,”ABBA”.”ABCD”.”BCD”,这几个单词,那么三叉树就会出现如下的储存方式:

虚线表示匹配的箭头,黄色的表示单词结尾

下面是python实现代码:

# -*- coding: utf-8 -*-
#Ternary Search Tree

# 小于的left, 大于的right, 等于的mid

#定义状态属性
_SENTINEL = ()

class TST(object):
    #定义三叉树位置结构
    __slots__ = ('splitchar','l','m','r','v')

    #初始化结构
    def __init__(self, ch=None):
        self.splitchar = ch
        self.l = self.m = self.r = None

    #返回状态
    def __getstate__(self):
        l = [self.splitchar,self.l,self.m,self.r]
        if hasattr(self,'v'):
            l.append(self.v)
        return tuple(l)

    #设置状态,目的支持pickle的持久化对象
    def __setstate__(self,l):
        self.splitchar = l[0]
        self.l = l[1]
        self.m = l[2]
        self.r = l[3]
        if len(l) > 4 :
            self.v = l[4]

    #定义类方法,递归方式插入字母,这样不用实例
    @classmethod
    def insert(klass,p,k,v):
        #获取字母
        ch = k[0]

        #若三叉树结构为空,则初始化
        if p is None:
            p = TST(ch)
        elif p.splitchar is None:
            p.splitchar = ch

        #若当前字符小于节点字符,则做插入
        if ch < p.splitchar:
            p.l = klass.insert(p.l,k,v)
        #若当前字符等于节点字符,则
        elif ch == p.splitchar:
            #获取剩余字符
            k = k[1:]
            if k:
                p.m = klass.insert(p.m,k,v)
            else:
                #标记字母位置
                p.v = v
        #否则右插入
        else:
            p.r = klass.insert(p.r,k,v)

        return p

    #添加数据
    def add(self,k,v):
        return self.insert(self,k,v)

    #搜索字符串
    def search(self,s,fallback=None):
        p = self
        while p:
            ch = s[0]
            if ch < p.splitchar:
                p = p.l
            elif ch == p.splitchar:
                s = s[1:]
                if not s:
                    if hasattr(p,'v') :
                        return p.v
                    break
                p = p.m
            else:
                p = p.r
        return fallback

    #搜索前缀的字符
    def prefix_search(self,s):
        p = self
        while p:
            ch = s[0]
            if ch < p.splitchar:
                p = p.l
            elif ch == p.splitchar:
                s = s[1:]
                if not s:
                    return list(p)
                p = p.m
            else:
                p = p.r
        return []

    #批量增加数据
    def bulk_add(self,l,start=0,stop=None,sorted=False):
        '''
        为了取得最佳性能,字符串应该以随机或者自平衡顺序插入到三叉树中
        尤其不能按照字母顺序,这样就和链表没啥区别了
        '''
        #若是没有排序的数据则进行排序
        if not sorted:
            l.sort()

        #若没有结束位置,则以全部长度作为结束
        if stop is None:
            stop = len(l)

        #比较开始到结束距离
        diff = stop - start

        #若为一个则直接添加
        if diff == 1 :
            self.add(l[start][0],l[start][1])
        #若为两个同样直接添加
        elif diff == 2 :
            self.add(l[start][0],l[start][1])
            self.add(l[start+1][0],l[start+1][1])
            return
        #两个以上则开始计算中间值
        else:
            mid_p = start + (diff / 2)
            #增加中间值
            self.add(l[mid_p][0],l[mid_p][1])
            #采用分治法递归增加,让我回忆起快速排序
            self.bulk_add(l,mid_p+1,stop,True)
            self.bulk_add(l,start,mid_p,True)

    def __contains__(self,k):
        if self.search(k,_SENTINEL) is _SENTINEL:
            return False
        return True

    def __iter__(self):
        stack = []
        p = self
        if not p:
            return
        while True:
            if p.r:
                stack.append(p.r)
            if p.m:
                stack.append(p.m)
            if p.l:
                stack.append(p.l)
            if hasattr(p,'v') :
                yield p.v
            if not stack:
                break
            p = stack.pop()

 

# 来源:韩少杰 | ThinkDevil


在微博上关注: 新浪, 腾讯   投稿

最新招聘

更多>>

相关 [python 代码 三叉] 推荐:

使用python代码实现三叉搜索树高效率”自动输入提示”功能

- est - python.cn(jobs, news)
最近项目中需要通过全拼音和简写拼音实现输入自动提示结果功能,查了一些资料发现三叉搜索树无论是在时间还是空间上都比较优秀. 三叉搜索树是trie树的演化版,除去了指针,这样在空间上节省不少,每个节点基本分为三个方向:左、中、右,当字符小于当前节点则存放左边,大于则存放右边,等于则存放中间. 具体实现原理可参考:http://igoro.com/archive/efficient-auto-complete-with-a-ternary-search-tree/.

python代码调试

- - 阿里古古
【转自: http://blog.csdn.net/luckeryin/article/details/4477233】. 本文讨论在没有方便的IDE工具可用的情况下,使用pdb调试python程序. 例如,有模拟税收计算的程序:. debug_demo函数计算4500的入账所需的税收. 在需要插入断点的地方,加入红色部分代码:如果_DEBUG值为True,则在该处开始调试(加入_DEBUG的原因是为了方便打开/关闭调试).

Python安全编码与代码审计

- - FreeBuf.COM | 关注黑客与极客
现在一般的web开发框架安全已经做的挺好的了,比如大家常用的django,但是一些不规范的开发方式还是会导致一些常用的安全问题,下面就针对这些常用问题做一些总结. 代码审计准备部分见《php代码审计》,这篇文档主要讲述各种常用错误场景,基本上都是咱们自己的开发人员犯的错误,敏感信息已经去除. 未对输入和输出做过滤,场景:.

python 代码自动生成的方法 (代码生成器)

- - 大CC
python 代码自动生成的方法 (代码生成器). 工作中遇到这么一个事,需要写很多C++的底层数据库类,但这些类大同小异,无非是增删改查,如果人工来写代码,既费力又容易出错;而借用python的代码自动生成,可以轻松搞定;. (类比JAVA中的Hibernate自动生成的数据库底层操作代码). 下面介绍使用python字符串替换的方法;.

3 行 Python 代码解简单的一元一次方程

- rex - python.cn(jobs, news)
刚才看到一篇《Linear equations solver in 3 lines (Python recipe)》,用3行代码实现了解一元一次方程:. 看上去很强大,于是就解读下代码吧. 首先是第一行,它将等式进行了变形,生成了一个结果为0的算式“x - 2*x + 5*x - 46*(235-24) -( x + 2)”.

谁说使用 Python 你就写不出混乱的代码?

- Ken - python.cn(jobs, news)
本文是从 Penrose Tiling in Obfuscated Python 这篇文章翻译而来. 谁说使用Python你就写不出混乱的代码. 下面这段Python代码是用来生成一些彭罗斯铺砖图案的. 不错,这是段可运行的Python代码:. 当这段代码运行时,它会产生一个1000×1000的png格式的彭罗斯铺砖图案,里面包含有大概2212个具有3D浮雕效果的彭罗斯铺砖图.

谁说使用Python你就写不出混乱的代码?

- bingo - 博客园新闻频道
  本文是从 Penrose Tiling in Obfuscated Python这篇文章翻译而来.   谁说使用Python你就写不出混乱的代码.   下面这段Python代码是用来生成一些彭罗斯铺砖图案的. 不错,这是段可运行的Python代码:.   当这段代码运行时,它会产生一个1000×1000的png格式的彭罗斯铺砖图案,里面包含有大概2212个具有3D浮雕效果的彭罗斯铺砖图.

50行Python代码写一个语言检测器

- - ITeye资讯频道
你有没有曾经好奇过Chrome浏览器是如何知道一个网页的语言,并对外国文字的网页提供翻译服务的. 或者,Facebook是如何翻译你朋友用写在你主页上的外国文字. 检测一种语言实际上非常简单,改进了用户体验,而且不需要用户做任何的事情. 我无意中发现的 ActiveState recipe for a language detector in Python这是非常不错的一段程序,但是我决定做点小小的改进.

从Zero到Hero,一文掌握Python关键代码

- -
选自free Code Camp. 本文整体梳理了 Python 的基本语法与使用方法,并重点介绍了对机器学习十分重要且常见的语法,如基本的条件、循环语句,基本的列表和字典等数据结构,此外还介绍了函数的构建和对象与类的声明. 这些在使用 Python 执行机器学习任务中十分常见,它可以为我们搭建一个基本的使用框架.

基于 Python 的 Scrapy 爬虫入门:代码详解

- - SegmentFault 最新的文章
接下来创建一个爬虫项目,以 图虫网 为例抓取里面的图片. 在顶部菜单“发现” “标签”里面是对各种图片的分类,点击一个标签,比如“美女”,网页的链接为: https://tuchong.com/tags/美女/,我们以此作为爬虫入口,分析一下该页面:. 打开页面后出现一个个的图集,点击图集可全屏浏览图片,向下滚动页面会出现更多的图集,没有页码翻页的设置.