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

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

【问题讨论】:

标签: c++ c data-structures trie


【解决方案1】:

如果您正在寻找 ANSI C 实现,您可以从 FreeBSD 中“窃取”它。您要查找的文件名为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

      【讨论】:

      【解决方案5】:

      参考资料,

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

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          【解决方案7】:

          CedarHAT-TrieJudyArray 非常棒,你可以找到基准 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

              【讨论】:

              • 我的反对票是无意的,现在被 StackOverflow 锁定了。我不知道如何撤消它。对不起。
              【解决方案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;
                        }
                    }
                
                };
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2021-11-21
                  • 1970-01-01
                  • 2011-01-14
                  • 2017-05-15
                  • 1970-01-01
                  • 2021-10-30
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多