当前位置:编程学习 > 网站相关 >>

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

 

原始出处: 韩少杰| ThinkDevil

最近项目中需要通过全拼音和简写拼音实现输入自动提示结果功能,查了一些资料发现三叉搜索树无论是在时间还是空间上都比较优秀。

三叉搜索树是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:

&n

补充:Web开发 , Python ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,