Реализация Trie

Есть ли на C / C ++ эффективные по скорости и кешированию реализации trie? Я знаю, что такое дерево, но не хочу изобретать велосипед, реализовывая его сам.


person Anton Kazennikov    schedule 24.06.2009    source источник
comment
code.google.com/p/simple-trie   -  person ahmedsafan86    schedule 14.04.2013


Ответы (12)


если вы ищете реализацию ANSI C, вы можете «украсть» ее у FreeBSD. Файл, который вы ищете, называется radix.c. Он используется для управления данными маршрутизации в ядре.

person SashaN    schedule 24.06.2009
comment
Я не думал об этом. Спасибо! - person Anton Kazennikov; 24.06.2009
comment
вы должны благодарить * людей из BSD, а не меня :-) - person SashaN; 24.06.2009
comment
@SashaN Ссылка не работает. - person Dannyboy; 12.06.2014
comment
попробуйте эту ссылку для radix.c: opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/net/radix.c - person Viren; 17.07.2014

Я понимаю, что речь шла о готовых реализациях, но для справки ...

Прежде чем перейти к Джуди, вы должны прочитать «Сравнение производительности Джуди с хеш-таблицами» . Тогда поиск в Google заголовка, скорее всего, даст вам целую жизнь обсуждений и опровержений, которые нужно прочитать.

Я знаю одно явно ориентированное на кеширование дерево - это HAT-trie.

HAT-trie при правильной реализации - это очень круто. Однако для поиска по префиксу вам потребуется этап сортировки хэш-сегментов, что несколько противоречит идее структуры префикса.

Несколько более простое дерево - это burst-trie, которое по сути дает вам интерполяцию между каким-либо стандартным деревом (например, BST) и деревом. Мне нравится концептуально, и это намного проще реализовать.

person eloj    schedule 14.08.2009
comment
HAT-Trie +1. это довольно круто .. - person Kokizzu; 27.02.2015

Мне повезло с libTrie. Возможно, он не был специально оптимизирован для кеширования, но производительность для моих приложений всегда была достойной.

person SPWorley    schedule 24.06.2009

GCC поставляется с несколькими структурами данных как частью «структур данных на основе политик». Это включает в себя несколько реализаций trie.

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

person tgoodhart    schedule 17.05.2011
comment
Не могли бы вы предоставить образец с #include? Спасибо за ответ. - person Serg; 14.09.2016
comment
Пример использования trie github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/ - person mosh; 09.07.2017

Использованная литература,

  • Статья о реализации двойного массива данных (включает C реализацию)
  • TRASH - динамическая структура данных LC-дерева и хэша - - (справочник в формате PDF от 2006 г., описывающий динамическое дерево LC, используемое в ядре Linux для реализации поиска адресов в таблице IP-маршрутизации.
person nik    schedule 24.06.2009

Массивы Джуди: очень быстрые и эффективные с точки зрения памяти упорядоченные разреженные динамические массивы для битов, целых чисел и строк. Массивы Judy быстрее и эффективнее с точки зрения памяти, чем любое дерево двоичного поиска (включая avl и красно-черные деревья).

person bill    schedule 24.06.2009
comment
Вау! Интересно. Я о них не знал. - person Anton Kazennikov; 24.06.2009

кедр, HAT-Trie и JudyArray - это здорово, вы можете найти тест здесь.

результат теста

person Kokizzu    schedule 27.02.2015

Вы также можете попробовать TommyDS на http://tommyds.sourceforge.net/

См. Страницу тестов на сайте для сравнения скорости с nedtries и judy.

person amadvance    schedule 10.01.2011
comment
(К вашему сведению, я являюсь автором nedtries) Обратите внимание, что в приведенных выше тестах использовалась версия nedtries C. Версия C ++ примерно на 15% быстрее, и если я правильно читаю график, она была бы лишь немного медленнее, чем версия TommyDS, если бы она была построена как C ++. Тем не менее, у него гораздо меньше накладных расходов на узел, чем у меня. Я намеренно переборщил с метаданными, чтобы включить действительно глубокую проверку утверждений во время операции отладки :) - person Niall Douglas; 17.04.2012

Оптимизация кеша - это то, что вам, вероятно, придется сделать, потому что вам нужно будет уместить данные в одну строку кеша, которая обычно составляет примерно 64 байта (что, вероятно, сработает, если вы начнете объединять данные, такие как указатели) . Но это сложно :-)

person Jasper Bekkers    schedule 24.06.2009

Burst Trie кажутся немного более компактными. Я не уверен, насколько эффективен кеш-память любого индекса, так как кеш-память ЦП настолько мала. Однако такой тип дерева достаточно компактен, чтобы хранить большие наборы данных в ОЗУ (в отличие от обычного дерева).

Я написал реализацию пакетного дерева на Scala, которая также включает в себя некоторые методы экономии места, которые я нашел в реализации GWT с опережающим вводом типов.

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

person Nate    schedule 29.04.2014
comment
Мой голос против был непреднамеренным и теперь заблокирован StackOverflow. Не знаю, как это исправить. Прости. - person Roman Mishin; 20.03.2016

У меня были очень хорошие результаты (очень хороший баланс между производительностью и размером) с marisa-trie по сравнению с несколькими реализациями TRIE, упомянутыми в моем наборе данных.

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

person benjist    schedule 25.10.2016

Делюсь моей "быстрой" реализацией для 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;
        }
    }

};
person Shady Sirhan    schedule 15.04.2017