Open Nashev opened 5 years ago
Хотя не, сильно дальше так не пройти: если строчку второго уровня уложить в то же дерево, получится строка, начинающаяся со своей первой буквы, ... хм.. надо пример расписать.
В пустое хранилище кладём «ехал», «ел», «еловый», «ехала», «ела» и «ехать». Это 6 слов длинной 4+2+6+5+3+4=24 символа.
Если не пойти:
В пустое хранилище кладём «ехал»
Добавляем туда «ел»
Добавляем «еловый»
Добавляем «ехала»
Добавляем «ела»
Добавляем «ехать»
А теперь то же самое, если пойти:
В пустое хранилище кладём «ехал»
Добавляем туда «ел»
Добавляем «еловый»
Добавляем «ехала»
Добавляем «ела»
Добавляем «ехать»
В пределе, кажись, получается что окончание отделяется после каждого символа, и цепочка каждого слова имеет свой нумерованный узел, и состоит из "(символ + (символ) + (символ + (символ + ...(символ)...)) — индекс", то есть столько рекурсивных обращений к словарю, сколько в нём букв. Но обращения рекурсивные, то есть есть шанс что не каждое из них придётся хранить отдельно.
Интересно было б посчитать количество внешних использований слов, и количество внутренних переиспользований частей слов. И посмотреть топы обоих списков.
Добавляем «нахал»
тут при добавлении слова ищется, нет ли для него в словаре готового окончания. Иначе говоря, после облома с нахождением максимально подходящего начала, с каждой буквы добавляемого слова ищется аналогичное начинающееся слово и раскручиваются его дети в поисках подходящего продолжения...
Добавляем «хахаль» - чтоб и начало было знакомым и середина, и новое окончание
то есть, если нашли начало - говорим, что новое слово это оно, плюс всё оставшееся окончание. Затем пристраиваем это оставшееся окончание как новое слово. Если не нашли начало - то смотрим, какую часть считать новым началом, исходя из того, какую часть окончания можно считать уже пристроенной.
Что-то статистика не сильно вдохновляющая получается.
Символ - это 2 байта (юникод), а то и 1 (UTF-8 при латинице) и плюс накладных расходов на строчку по 12 байт
Узел, про том что номер узла (слова или фрагмента слова) - минимум 4 байта, получается 16 байт - родитель (начало этого слова), сосед (соседнее слово с тем же началом), ребёнок (варианты более длинных слов, начинающиеся на это) и содержимое (окончание этого слова). И куча рекурсивных накладных расходов на кодирование и декодирование.
Неоднозначненько для меня это всё по-прежнему. Надо смотреть, что получится по факту.
Совать строчки (слова, словоформы, URI) в общее дерево, размазывая их по ветвям от корня. А указателем на строку иметь адрес финального листочка. Тогда можно раскатать от него до корня, и восстановить строчку.
Так в файловой системе, по сути, хранятся полные имена файлов — пути размазаны по дереву каталогов. Собственно, можно это дерево строк и на дерево папок отражать...
В пределе, в корне и на каждом уровне получится алфавит, а глубина дерева станет равна длине самого длинного слова. Но до тех пор совпадающие части от начала строчки будут храниться в одном экземпляре.
Предположительно, это даст сэкономить на памяти за счет однократного хранения строк.
Можно пойти дальше — строчки узлов глубже корня тоже хранить в этом же дереве, храня вместо строк указатели на их финальные листочки.
Разматывание слова получится рекурсивным в квадрате...
Размазывание (интеграция в это дерево) получится тоже сложнее... Но, кажется, все равно возможно.
Для отвязки от памяти и облегчения сериализации, особенно независимой, можно ссылкой на такую строку считать не указатель на узел, а его индекс в массиве узлов дерева. Если он будет только расти, номера устаревать не будут. Хэндлы. Сериализуемые.
Растить массив узлов можно блоками, и в номере узла выделять номер блока и номер в блоке. Блоки подгружать отдельно, по мере необходимости. Если узлы понадобиться удалять или менять им смысл, можно помечать их удалёнными и дальше иметь механизмы дефрагментации и хранить таблицу соответствий прежних номеров новым, обращаясь к новой базе через неё.
У узла нужны ссылки на соседа, первого ребёнка и на родителя. А так же ссылка на содержимое (строку у корневых узлов или хэндл строки у дочерних) и счётчик использований снаружи.
Хотя, счётчики можно и нужно иметь отдельно, в отдельной таблице. Они не нужны самому дереву, и могут быть контекстно-зависимыми...