gjrbyek ajhev
Отредактировано Webarion (13.06.2025 13:17:36)
PureBasic - форум |
Привет, Гость! Войдите или зарегистрируйтесь.
Вы здесь » PureBasic - форум » OpenSource » Radix Tree AI
gjrbyek ajhev
Отредактировано Webarion (13.06.2025 13:17:36)
Webarion
Mid медленная потому что создаёт строковое представление данных, то есть требует манипуляции, в то время как обращение непосредственно к бинарным данным не конвертируя в строку естественно будет быстрее. К примеру "apple" берём первую букву, но не "a" а 97, литеральная 'a' является бинарным числом, вот мы и получаем прямой доступ по указателю используя *c\c и в дереве также должен быть доступ к элементам в бинарном виде, то есть от корня ищем 97 что является "a". Вроде логически понимаю, но как это записать в код пока не ясно.
Посмотри описание "посимвольный разбор"
Webarion
За основу можно взять этот алгоритм. Это создаёт дерево файлов, то есть структурно это копия дерева "Radix Tree" с разницей, что запрашиваются файлы файловой системы. Если представить "apple" как "a\p\p\l\e", то это и есть дерево. Разделитель нам ставить не нужно, мы проверяем если в дереве есть папка "a" то входим в неё и ищем в ней следующий элемент и продолжаем до тех пор, когда буквы не будет в узле, в этот момент мы добавляем элемент целиком остаток. Это полностью описывает работу функции.
Экспериментируя столкнулся с ситуацией. Например есть 2 слова
аббв
аббг
можно построить легким и неэкономным способом:
а->б->б->в|г
или сложным и быстрым для доступа
а->бб->в|г
Первый способ на каждую букву свой бинарный элемент структуры, даже если он пустой и лишь ссылается на следующую букву. При этом имея в нагрузку два указателя на списки.
Второй способ экономнее, имеет поле строку любой ширины, но при добавлении слова сложнее перестраивать список. Часть слов, которые в узле придётся перестроить, потому что вводимое слово перестраивает узел. Например добавим слово "абв" и нам придется убрать поле "бб"
а->б
->б->в|г
->с
тут надо уметь приатачить узел в|г с "бб" на "б", удалить "бб" добавив "б" и "с". В общем вроде рассуждать понятно, а вот сделать работающий алгоритм голову сломаешь.
Вот мои потуги, просто добавить слово с учётом его разбора там ещё думать и думать
Structure Tree s.s ; строка и снизу привязанные к ней узлы и элементы size.i ; размер элемента узла, а нужен ли, разве что для чтение с PeekS(), но s.s нультерминированная, поэтому size не нужен List item.s() ; список остатков строки List node.Tree() ; узел (папка) EndStructure Procedure.q AddWord(*s.Tree, *c.Character) ; передали пустое дерево (изначально пустое) и слово Protected *n.Character If *s=0 Or *c=0 Or *c\c=0 ; проверка, дерево существует, указатель на слово существует, слово в указателе существует. ProcedureReturn EndIf If ListSize(*s\node()) ForEach *s\node() *n = @*s\node()\s ; получаем указатель на строку элемента списка узла While *c\c And *n\c ; если оба ещё валидны, то делаем шаг дальше If *c\c <> *n\c ; если очередной символ не одинаков, то Break EndIf *n\c + 2 *c\c + 2 Wend If *c\c = 0 And *n\c = 0 ProcedureReturn ; слово уже есть, выпрыгиваем ElseIf *c\c = 0 ; если слово короче чем узел, то надо перестроить узел, взяв короткое слово за узел ElseIf *n\c = 0 ; если узел короче чем слово, то добавляем остаток в item указанного node AddWord(*s\node(), *c.Character) Else ; Если выход по Break тогда разделяем узел EndIf Next Else If ListSize(*s\item()) ; Здесь должен быть алгоритм поиска возможности узла, но пока просто добавим слово If AddElement(*s\item()) *s\item() = PeekS(*c) ; считываем остаток слова EndIf ForEach *s\item() *n = @*s\item() ; получаем указатель на строку элемента списка узла While *c\c And *n\c ; если оба ещё валидны, то делаем шаг дальше If *c\c <> *n\c ; если очередной символ не одинаков, то Break EndIf *n\c + 2 *c\c + 2 Wend If *c\c = 0 And *n\c = 0 ProcedureReturn ; слово уже есть, выпрыгиваем ElseIf *c\c = 0 ; если слово короче чем узел, то надо перестроить узел, взяв короткое слово за узел ElseIf *n\c = 0 ; если item короче чем слово, то добавляем остаток в item указанного item If AddElement(*s\node()) *s\node()\s = *s\item() If AddElement(*s\item()) *s\item() = PeekS(*c) ; считываем остаток слова EndIf EndIf Else ; Если выход по Break тогда разделяем узел EndIf Next Else If AddElement(*s\item()) *s\item() = PeekS(*c) ; считываем остаток слова EndIf EndIf EndIf EndProcedure Procedure View(*s.Tree, Pos) ; Отображение содержимого дерева. AddGadgetItem(0, -1, *s\s, 0, Pos) Pos+1 ForEach *s\node() ; Отображение всех подузлов текущего узла View(*s\node(), Pos) ; Рекурсивный вызов процедуры Next ForEach *s\item() ; Отображение списка элементов текущего узла AddGadgetItem(0, -1, *s\item(), 0, Pos) Next EndProcedure If OpenWindow(0, 0, 0, 400, 400, "", #PB_Window_MinimizeGadget|#PB_Window_ScreenCentered) TreeGadget(0, 0, 0, 400, 400) Dictionary.Tree ; Создание пустого дерева как одного экземпляра структуры Dictionary\s = "узел" AddWord(Dictionary, @"apple") AddWord(Dictionary, @"banana") View(Dictionary, 0) Repeat Event = WaitWindowEvent() Until Event = #PB_Event_CloseWindow EndIf
Отредактировано AZJIO (02.03.2025 11:05:51)
Webarion
С сортировкой дольше добавляется, так надо сортировать дерево. Это очевидно. А доступ не угадаешь, запрашиваемый символ может оказаться в начале одноуровнего списка, а может в конце. К примеру z был в начале, отсортировал и стал в конце, запрашиваешь z и он идут до конца списка, так что у тебя не обязательно узлы будут начинаться на "a" поэтому нет приоритета в какой-то сортировке, они там равнозначные. Искать ты всё равно будешь до первого попавшегося.
AZJIO написал(а):
можно построить легким и неэкономным способом:
а->б->б->в|гЭто похоже на алгоритм Trie:
а
\
б
\
б
/ \
в г
В итоге, в этом варианте у дерева, 5 узлов.
AZJIO написал(а):или сложным и быстрым для доступа
а->бб->в|гДумаю, что в этом варианте, ты про Radix Tree:
абб
/ \
в г
Так суть то у них одинакова, ты всё равно также добавляешь и также извлекаешь слово, а алгоритм разный. И последний выигрывает по скорости, по меньшему объёму памяти, но по более сложному алгоритму. В первом иди в цикле по одной букве и генерируй очередную стркутуру, а во втором надо перестраивать дерево (в пером нет).
запишет ключи на "а", в самый конец последовательности
Какова вероятность что "а" имеет приоритет? Что если отсортируешь, а у тебя постоянно нужен "z"? Он был первый, а ты его сделал последним и начинаешь при каждом запросе проходить весь список? У тебя "а" котируется только при условии что ты всегда просишь "а", но в реальности "а" не является приоритетом. У тебя ощущение что если ты отсортировал, то будет быстрее, на самом деле нет. Будет быстрее при условии что начальные буквы алфавита будут встречаться чаще, но получается как если бы ты говорил собеседнику "строй свои фразы так чтобы все слова начинались на "а", у меня так мозг быстрее работает". Максимум можешь взять какую нибудь книгу и сделать подсчёт встречаемости букв, и сортировать с этим условием. Хотя я думаю выгадаешь не много, так как гласные чаще во второй букве слова, поэтому если в первом уровне использовать один алгоритм сортировка, то во втором уровне должен уже другой. Получается надо создавать частоту встречаемости буквы в слове учитывая ещё и позицию буквы в слове.
Radix Tree, реализация алгоритма. | OpenSource | 15.05.2025 |
Обсуждение нейросетей | OffTop | 03.03.2025 |
Сопоставление слов | Вопросы по PureBasic | 02.03.2025 |
Вы здесь » PureBasic - форум » OpenSource » Radix Tree AI