尝试实现[关闭]

Posted

技术标签:

【中文标题】尝试实现[关闭]【英文标题】:Trie implementation [closed] 【发布时间】:2010-11-05 09:49:38 【问题描述】:

在 C/C++ 中是否有任何速度和缓存高效的 trie 实现? 我知道 trie 是什么,但我不想重新发明***,自己实现它。

【问题讨论】:

code.google.com/p/simple-trie 【参考方案1】:

如果您正在寻找 ANSI C 实现,您可以从 FreeBSD 中“窃取”它。您要查找的文件名为radix.c。用于管理内核中的路由数据。

【讨论】:

@SashaN 链接不起作用。 试试这个 radix.c 的链接:opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/net/radix.c【参考方案2】:

我意识到问题是关于现成的实现,但仅供参考......

在你跳上朱迪之前,你应该阅读“A Performance Comparison of Judy to Hash Tables”。然后在谷歌上搜索标题可能会给您带来一生的讨论和反驳。

我所知道的一个明确的缓存意识 trie 是HAT-trie。

正确实施 HAT-trie 非常酷。但是,对于前缀搜索,您需要对哈希桶进行排序,这与前缀结构的想法有些冲突。

一个更简单的树是burst-trie,它本质上为您提供了某种标准树(如 BST)和树之间的插值。我喜欢它的概念,而且它更容易实现。

【讨论】:

【参考方案3】:

libTrie 我很幸运。它可能没有经过专门的缓存优化,但对于我的应用程序来说性能一直不错。

【讨论】:

【参考方案4】:

GCC 附带了一些数据结构作为其“基于策略的数据结构”的一部分。这包括一些 trie 实现。

http://gcc.gnu.org/onlinedocs/libstdc++/ext/pb_ds/trie_based_containers.html

【讨论】:

您能提供一个#include 的样品吗?谢谢你的回答。 trie github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/…的示例使用【参考方案5】:

参考资料,

一篇Double-Array Trie implementation 文章(包括一个C 实现) TRASH - 动态 LC-trie 和哈希数据结构 --(2006 年的 PDF 参考,描述了 Linux 内核中用于在 IP 路由表中实现地址查找的动态 LC-trie

【讨论】:

【参考方案6】:

Judy arrays:用于位、整数和字符串的非常快速且内存高效的有序稀疏动态数组。 Judy 数组比任何二叉搜索树(包括 avl 和红黑树)都更快且内存效率更高。

【讨论】:

【参考方案7】:

Cedar、HAT-Trie 和 JudyArray 非常棒,你可以找到基准 here。

【讨论】:

【参考方案8】:

您也可以通过 http://tommyds.sourceforge.net/ 试用 TommyDS

查看网站上的基准页面,与 nedtries 和 judy 进行速度比较。

【讨论】:

(仅供参考,我是 nedtries 的作者)请注意,上面的基准测试使用的是 C 版本的 nedtries。 C++ 版本快了大约 15%,如果我没看错,如果用 C++ 构建,它只会比 TommyDS 的版本慢一点。也就是说,他每个节点的开销比我低得多。我故意在元数据中过度使用以在调试操作期间启用真正深入的断言检查:)【参考方案9】:

缓存优化是您可能必须要做的事情,因为您必须将数据放入单个缓存行中,该缓存行通常约为 64 字节(如果您开始组合数据,这可能会起作用,例如作为指针)。但这很棘手:-)

【讨论】:

【参考方案10】:

Burst Trie's 似乎更节省空间。我不确定您可以从任何索引中获得多少缓存效率,因为 CPU 缓存非常小。但是,这种 trie 足够紧凑,可以将大型数据集保存在 RAM 中(常规 Trie 不会)。

我编写了一个 Burst trie 的 Scala 实现,它还结合了我在 GWT 的 type-ahead 实现中发现的一些节省空间的技术。

https://github.com/nbauernfeind/scala-burst-trie

【讨论】:

我的反对票是无意的,现在被 *** 锁定了。我不知道如何撤消它。对不起。【参考方案11】:

与我的数据集提到的几个 TRIE 实现相比,我使用 marisa-trie 获得了非常好的结果(性能和大小之间的非常好的平衡)。

https://github.com/s-yata/marisa-trie/tree/master

【讨论】:

【参考方案12】:

分享我对 Trie 的“快速”实现,仅在基本场景中进行了测试:

#define ENG_LET 26

class Trie 
    class TrieNode 
    public:
        TrieNode* sons[ENG_LET];
        int strsInBranch;
        bool isEndOfStr;

        void print() 
            cout << "----------------" << endl;
            cout << "sons..";
            for(int i=0; i<ENG_LET; ++i) 
                if(sons[i] != NULL)
                    cout << " " << (char)('a'+i);
            
            cout << endl;
            cout << "strsInBranch = " << strsInBranch << endl;
            cout << "isEndOfStr = " << isEndOfStr << endl;
            for(int i=0; i<ENG_LET; ++i) 
                if(sons[i] != NULL)
                    sons[i]->print();
            

        
        TrieNode(bool _isEndOfStr = false):isEndOfStr(_isEndOfStr), strsInBranch(0) 
            for(int i=0; i<ENG_LET; ++i) 
                sons[i] = NULL;
            
        
        ~TrieNode() 
            for(int i=0; i<ENG_LET; ++i) 
                delete sons[i];
                sons[i] = NULL;
            
        
    ;

    TrieNode* head;
public:
    Trie()  head = new TrieNode();
    ~Trie()  delete head; 
    void print() 
        cout << "Preorder Print : " << endl;
        head->print();
    
    bool isExists(const string s) 
        TrieNode* curr = head;
        for(int i=0; i<s.size(); ++i) 
            int letIdx = s[i]-'a';
            if(curr->sons[letIdx] == NULL) 
                return false;
            
            curr = curr->sons[letIdx];
        

        return curr->isEndOfStr;
    
    void addString(const string& s) 
        if(isExists(s))
            return;
        TrieNode* curr = head;
        for(int i=0; i<s.size(); ++i) 
            int letIdx = s[i]-'a';
            if(curr->sons[letIdx] == NULL) 
                curr->sons[letIdx] = new TrieNode();    
            
            ++curr->strsInBranch;
            curr = curr->sons[letIdx];
        
        ++curr->strsInBranch;
        curr->isEndOfStr = true;
    
    void removeString(const string& s) 
        if(!isExists(s))
            return;
        TrieNode* curr = head;
        for(int i=0; i<s.size(); ++i) 
            int letIdx = s[i]-'a';

            if(curr->sons[letIdx] == NULL) 
                assert(false);
                return; //string not exists, will not reach here
            
            if(curr->strsInBranch==1)     //just 1 str that we want remove, remove the whole branch
                delete curr;
                return;
            
            //more than 1 son
            --curr->strsInBranch;
            curr = curr->sons[letIdx];
        
        curr->isEndOfStr = false;
    

    void clear() 
        for(int i=0; i<ENG_LET; ++i) 
            delete head->sons[i];
            head->sons[i] = NULL;
        
    

;

【讨论】:

以上是关于尝试实现[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

RecyclerView如何实现多选? [关闭]

如何在 Java 中正确处理蛮力登录尝试? [关闭]

我们可以用 select2 实现树视图吗? [关闭]

如何实现SlidingMenu? [关闭]

BLAST对齐算法的Python实现? [关闭]

打印对话框关闭后自动关闭窗口