基于 double array 实现汉字的trie树索引 与 查询功能 python实现

来源:互联网 发布:阿尔法猎手 软件 编辑:程序博客网 时间:2024/06/05 03:38

一、 基本原理。

基本原理利用字符串集合中字符串的公共前缀来降低时间开销以达到提高效率的目的。

性质:1,根结点不包含任何字符信息;2,如果字符的种数为n(如英文的26个字母),则每个结点的出度为n(这样必然会导致浪费很多空间,这也是trie的缺点,我还没有想到好点的办法避免);3,查找,插入复杂度为O(n),n为字符串长度。

具体请百度之。



二、基于 trie字典的汉字串检索代码(python):

# coding=gbkdicts = ['啊','阿根廷','阿胶','阿拉伯','阿拉伯人','埃及']# 字后缀数组sufarr = {'啊':[],'阿':['根','胶','拉'],'埃':['及'],          '根':['廷'],'胶':[],'拉':['伯'],'及':[],          '廷':[],'伯':['人'],'人':[]}# 按ID编码codes = [ '啊','阿','埃','根','胶','拉','及','廷','伯','人' ]# 字的层次标示level = [1, 1, 1, 2, 2, 2, 2, 3, 3, 4]# 构建双数组base = [0]*21           # len:21 ; 21=2*10+1 的素数check = [0]*21# 记录已确定的字的base索引bid_mark = {'啊':0,'阿':1,'埃':2, '根':0,'胶':0,'拉':0,'及':0,'廷':0,'伯':0,'人':0}base[:3]=[1]*3          # 首字部分,简单置为1def pre_mark(pre_word,wi,word):    ''' 判断base中wi下标的前缀都在pre_words词表直到首字 且word为wi下标对应的字 '''    bkeys = bid_mark.keys()        if word not in bkeys or bid_mark[word]!=wi:             # 当前字的base值不匹配        return False    pre_wi = check[wi]                     # 逆序遍历base的前缀    pid = -1                               # 逆序遍历字的前缀     while pre_wi!=0 and (-1)*pid<=len(pre_word):        if pre_word[pid] not in bkeys or bid_mark[pre_word[pid]]!=pre_wi:            return False        pre_wi = check[pre_wi]        pid -= 1    if (-1)*pid>len(pre_word): return True # 完成前缀的遍历    else: return Falsefor w in dicts:             cw = [ w[i:i+2] for i in range(0,len(w),2) ]            # 分割出字    for iid in range(1,len(cw)):        par_w = cw[iid-1]                   # 字的前缀        iid_w = cw[iid]                     # 当前的字        par_id = codes.index(par_w)         # 字的前缀的编码        wid = codes.index(iid_w)        bval = bid_mark[par_w]        #if iid_w=='及': print "ID: %d, word: %s, pre-wrod: %s, code: %d, pre-code: %d, pre-base:%d"%(        #    iid,iid_w,par_w,wid,par_id,bval)        for wi in range(base[bval]+wid,21):   # 遍历所有可能的base位置            # 找到其base-id,置位            p_mk = pre_mark(cw[:iid],wi,iid_w)              print "TEST::pre_mark() base-id: %d, word: %s, result: %s"%(wi,iid_w,str(p_mk))            if p_mk:                              # 该词及其前缀部分已经设置值                break            if (not base[wi] and not check[wi]):  # 该位置未使用或吻合前缀                check[wi] = bval                 # 设置字的 base[] 值                for tval in range(1,21-wi):    # 遍历所有可能的取值                    flag = True                    for suf_w in sufarr[iid_w]:                        chi_id = codes.index(suf_w)     # 字的后缀的编码                        if  base[tval+chi_id]!=0 or check[tval+chi_id]!=0:                            flag = False                            break              # tval不满足child的base check 为0,再尝试其他值                    if flag:                        base[wi] = tval        # 成功,保存该base[]                        if wi==6 or wi==-1 or wi==9:                            print "ID: %d, word: %s, pre-word: %s, base: %d, base-val: %d, check: %d"%(                                iid,iid_w,par_w,wi,tval,check[wi])                        break                if not base[wi]:               # 无合适的 base                     print "ERROR:: set %s's base[]" % iid_w                    exit(1)                bid_mark[iid_w] = wi #; print "finnished one! %s=%d" % (iid_w,wi)                break                          # base check均成功        if not base[wi]:             print "ERROR:: get %s's position in base[]" % iid_w            exit(2)# 修改词尾标志for w in bid_mark.keys():    if len(sufarr[w])==0:        eid = bid_mark[w]        base[eid] *= -1# 查询给定词    def next_check(wid, code):    ''' 验证两个base[]索引id间是否有连接 '''    if code<0 or code>=len(codes):          # 字编码无效        return False    chiid = abs(base[wid])+code    if check[chiid]!=wid:        return False    return Trueqw = dicts[1] ;     # 查询词res = ''            # 返回结果words=[ qw[w:w+2] for w in range(0,len(qw),2) ]head_bid = bid_mark[words[0]] ; res = ''.join(words[0])for w in words[1:]:    cod = codes.index(w)    if not next_check(head_bid,cod):        print "word: %s no find!" % qw        break    head_bid = abs(base[head_bid])+cod      # 更新id    res = ''.join([res,w])    if base[head_bid]<0:        print "find a word: %s in Search word: %s"%(res,qw)               
参考: http://blog.csdn.net/joylnwang/article/details/6825991