За последние 24 часа нас посетили 22696 программистов и 1039 роботов. Сейчас ищут 493 программиста ...

Префиксное дерево trie низкоуровневая структура данных в PHP

Тема в разделе "PHP для профи", создана пользователем johovich, 20 июн 2018.

  1. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.410
    Симпатии:
    1.768
    звезду на гитхабе ляпни ему, не поленись

    можно но не нужно пока
    единственно что, это для рекурсивной функции хорошо бы использовать обёртку, чтобы она уже вызывала рекурсию, чтобы только нужные для обёртки параметры передавать.
    --- Добавлено ---
    да, это сейчас считается верным подоходом
     
    #101 igordata, 24 июл 2018
    Последнее редактирование: 24 июл 2018
  2. johovich

    johovich Активный пользователь

    С нами с:
    24 авг 2016
    Сообщения:
    146
    Симпатии:
    17
    Словарь в действии. Вот 12
    Спасибо, а я наоборот не люблю верблюда, мозг не привык, дополнительное усилие приходится делать, чтобы читать.
    Не дождусь когда закончу уже то, для чего это дерево создавалось.


    В действущей редакции функция выглядит так.

    PHP:
    1. public function &trie_traverse_node(int $id, string $concat, array &$res = []): array {
    2.     list($bits, $refs) = $this->node_get_children($id);
    3.  
    4.     //on the last node (leaf) save $concat to the res
    5.     if (isset($bits[$this->codepage['flag']])){
    6.         $res[] = $concat;
    7.     }
    8.     //if there is no references return result
    9.     if (empty($refs)) {
    10.         return $res;
    11.     }
    12.  
    13.     $bits = array_keys($bits);
    14.     //recurse call node traverse on each node_id and pass $concat arg by concatenating it a new char
    15.     foreach ($refs as $i => $node_id) {
    16.         $string = $concat . $this->codepage_flip[$bits[$i]];
    17.         $this->trie_traverse_node($node_id, $string, $res);
    18.     }
    19.  
    20.     return $res;
    21. }
    Поробовал сделать с одной точкой выхода, но мне показалось, что становится менее понятно, стараюсь избегать даже else у if, если это возможно.
     
  3. johovich

    johovich Активный пользователь

    С нами с:
    24 авг 2016
    Сообщения:
    146
    Симпатии:
    17
    А там реально все 3 аргумента нужные. В первом передается id узла, который надо пройти, поскольку в самом узле нет информации о том, какую букву он собой представляет, то во втором аргументе буква узла, в третьем аргумента передается ссылка на результирующий массив, в который собирается весь путь от начального узла до листьев дерева. При первом вызове ты указываешь первый узел с которого надо начать и букву этого узла, если третий аргумент не задан, то будет пустой массив.

    Ко второму аргументу на каждой следущем рекурсивном вызове от каждого пройденного узла добавляется его буква, в результате, когда дело доходит до листа (до узла, у которого в битовой маске поднят 48 бит), в этой строке как раз весь путь.
     
  4. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.410
    Симпатии:
    1.768
    третий аргумент нужен только для работы рекурсии - внутреннего метода со своей внутренней механикой и внутренней необходимостью сущестования третьего аргумента. Для внешнего метода торчащего наружу он не нужен.

    т.е. логично сделать как-то так:

    function ajaja($arg1, $arg2) { return ololo($arg1, $arg2, null); }

    Это раз

    Два, мне например непонятно, когда и как вызывать твой метод, если из него самого не следует его буква. В каком случае его использовать? Почему нельзя вызвать просто по id? Или просто по букве?
     
  5. johovich

    johovich Активный пользователь

    С нами с:
    24 авг 2016
    Сообщения:
    146
    Симпатии:
    17
    Метод внутренний, он паблик только для удобства. Будет внешний метод, который по букве сможет траверс делать. Дело в том, что если писать в узле его букву - это ещё 6 доп. Байт на маску. Если представить узлы ящичками в шкафу, то в ящичках нет ничего кроме букв следующих ящичков и ссылок на их номера. Чтобы понять какие именно буквы в самых первых ящичках эти ящички идут в алфавитном порядке. Т.е. первая буква "а" с индексом узла 0. traverse_node(0, 'а') выдаст всю ветку дерева на букву 'а'.

    P.s. Нормально, но не по канону. Сейчас понял как можно переделать.
     
  6. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.410
    Симпатии:
    1.768
    надо спрятать и наружу выставить правильные удобные дёргалки :D

    тогда зачем её указывать в методе?
     
  7. johovich

    johovich Активный пользователь

    С нами с:
    24 авг 2016
    Сообщения:
    146
    Симпатии:
    17
    Потому что для нулевого узла известно, что тут 'а'. А когда ты не с первого узла начинаешь, к примеру надо выдать все слова начинающиеся на 'бар', надо делать так traverse_node(6443, 'бар')
    Отдаст массив всех слов с началом на бар. Естественно сначала ещё надо узнать, какой индекса у узла буквы р.
    --- Добавлено ---
    Так и сделаю после. Данные функции очень частотные, поэтому я стараюсь их оставлять такими полуфабрикатами, чтобы не дублировать работу по возможности нигде.
     
  8. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.410
    Симпатии:
    1.768
    всё равно не понял зачем и число и слово