码迷,mamicode.com
首页 > 编程语言 > 详细

[从头学数学] 第255节 Python实现数据结构:字典树(Trie)

时间:2016-08-03 10:39:03      阅读:162      评论:0      收藏:0      [点我收藏+]

标签:

剧情提要:
阿伟看到了一本比较有趣的书,是关于《计算几何》的,2008年由北清派出版。很好奇
它里面讲了些什么,就来看看啦。


正剧开始:
星历2016年08月03日 09:35:13, 银河系厄尔斯星球中华帝国江南行省。

[工程师阿伟]正在和[机器小伟]一起研究[计算几何]]。


技术分享


关于字典树的实现,已经有非常多的博文涉及到了。但基本都是用内嵌数组/列表实现的。

本博文是它的递归实现。


技术分享


<span style="font-size:18px;">###
# @usage   字典树
# @author  mw
# @date    2016年08月02日  星期二  08:56:34 
# @param
# @return
#
###
class Trie:
    class TrieNode:
        def __init__(self,item,next = None, follows = None):
            self.item = item
            self.next = next
            self.follows = follows

        def __str__(self):
            return str(self.item);

        def getnext(self):
            return self.next;

        def setnext(self, next):
            self.next = next;            

        def getfollows(self):
            return self.follows;

        def setfollows(self, follows):
            self.follows = follows;

        def getitem(self):
            return self.item;

        def setitem(self, item):
            self.item = item;

        def __iter__(self):
            yield self.item;

            if (self.follows != None):
                for x in self.follows:
                    yield x;

        def iternext(self):
            yield self.item;

            if (self.next != None):
                for x in self.next.iternext():
                    yield x;

        #从两个方向观察节点信息,一是从它的后续看,这是看一个单词
        #另一个是从它的兄弟看,这是在这个点的各分支
        def info(self, direction = 0):            
            s = '';

            if direction == 0:
                for x in self:
                    s += str(x)+'-->';
            else:
                for x in self.iternext():
                    s += str(x)+'-->';
            
            print(s);

    def __init__(self):
        self.start = Trie.TrieNode('^', None, None);

    def insert(self,item):
        self.start = Trie.__insert(self.start,item)

    def __contains__(self,item):
        return Trie.__contains(self.start,item)

    #生成诩根所在的结点
    def __genNode(item):
        if (len(item) == 1):
            return Trie.TrieNode(item[0], None, None);
        elif (len(item) > 1):
            return Trie.TrieNode(item[0], None, Trie.__genNode(item[1:]));
        else:
            return None;        

    def __insert(node,item):
        # This is the recursive insert function.
        if (item == None or item == ''):
            return None;
        elif (node == None):
            return Trie.__genNode(str(item));
        elif (node.item == item[0]):
            node.setfollows(Trie.__insert(node.getfollows(), item[1:])); 
        else:                
            node.setnext(Trie.__insert(node.getnext(), item));

        return node;

    def __contains(node, item):
        # This is the recursive membership test.
        #单词结尾用'$'分隔,当然,如果用其它分隔符,此处必须更改item+'$'
        if Trie.__getNode(node, item) != None:
            return True;
        else:
            return False;

    #一般都是从字典的根结点开始遍历才有意义
    def getNode(self, node, item):                
        return Trie.__getNode(node, item);
    
    #找到某一节点
    def __getNode(node, item):
        if item == None or item == '':
            return None;
        elif node == None:
            return None;
        elif node.item != item[0]:
            return Trie.__getNode(node.next, item);
        else:
            if (len(item) > 1):
                return Trie.__getNode(node.follows, item[1:]);
            else:                
                return node;

    #遍历查看字典
    def dict(self):
        #单词结束的末尾标记
        endChar = '$';

        count = 0;
        
        if (self.start != None):            
            cursor = self.start;

            #具有后续节点的词段
            dict_1 = [];
            #最终版
            dict_2 = [];
            
            while cursor != None:
                #if (cursor.follows == None):
                if (cursor.follows == None):
                    #过滤掉词尾结束标记
                    dict_2.append(str(cursor.item)[:-1]);
                else:
                    dict_1.append(str(cursor.item));

                cursor = cursor.next;

            while (len(dict_1) > 0):
                a = dict_1.pop(0);
                
                cursor = Trie.__getNode(self.start, a);
                count+=1;
                if (cursor != None):
                    cursor = cursor.follows;
                    
                    while cursor != None:
                        if (cursor.follows == None):
                            dict_2.append((a+str(cursor.item))[:-1]);
                        else:
                            dict_1.append(a+str(cursor.item));

                        cursor = cursor.next;

            print('找结点{0}次'.format(count));
            print('字典:', dict_2);
        else:
            print('字典为空');
</span>


用例:

<span style="font-size:18px;">def main():
    #计时开始
    startTime = time.clock();

    t = Trie();
    
    a = ['I', 'love', 'lot', 'lance', 'you', 'you', 'love', 'me',
         'i', 'have', 'a', 'book', 'you', 'have', 'a', 'pencil',
         'pen', 'paper', 'lottol', 'banana'];

    #插入单词,词尾加结束符
    for i in range(len(a)):
        t.insert(a[i]+'$');

    
    t.start.next.next.follows.next.info();
    t.start.info(1);     
    
    n1 = t.getNode(t.start, 'lottol');
    if (n1 != None):
        n1.info();
        n1.info(1);
    else:
        print('无该节点');

    t.dict();

    print('banana'+'$' in t);
    print('how'+'$' in t);  
    
    #计时结束
    endTime = time.clock();

    #打印结果
    print('操作用时:{0:.3e} s'.format(endTime-startTime));
	
</span>

短短数行代码,写得非常头痛。用递归是不是比用列表有更大好处,阿伟也不清楚。

但是有一点可以肯定,用递归可以把整个字典连成一棵树,而列表做不到。


即将奥运会了,阿伟决定好好地去研究一下奥运会,另外,最近也出了不少好看的电视剧,

也要抽点时间去看看。


本节到此结束,欲知后事如何,请看下回分解。



[从头学数学] 第255节 Python实现数据结构:字典树(Trie)

标签:

原文地址:http://blog.csdn.net/mwsister/article/details/52100592

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!