MAXimal :: algo :: Суффиксное дерево. Алгоритм Укконена

Деревянный

Деревянный — разбор слова по составу онлайн

корень — ДЕРЕВ; суффикс — ЯНН; окончание — ЫЙ;
Основа слова: ДЕРЕВЯНН
Вычисленный способ образования слова: Суффиксальный

∩ — ДЕРЕВ; ∧ — ЯНН; ⏰ — ЫЙ;

Слово Деревянный содержит следующие морфемы или части:

  • ¬ приставка (0): —
  • ∩ корень слова (1): ДЕРЕВ;
  • ∧ суффикс (1): ЯНН;
  • ⏰ окончание (1): ЫЙ;

Онлайн разбор слова по составу (морфемный разбор) Деревянный произведен программными средствами, поэтому может содержать ошибки.
Если Вы нашли ошибку или морфемный разбор слова Деревянный произведен неверно (правильность указания корня, приставки, суффикса, основы слова), пожалуйста сообщите об этом в комментариях к разбору, мы постараемся учесть Ваши замечания

В других словарях:
Деревянный — Ефремова Т. Ф. Новый словарь русского языка
Деревянный — Толковый словарь русского языка С. Ожегова
Деревянный — Ожегов С. И., Шведова Н.

Антананариву

Ю. Толковый словарь русского языка
Деревянный — Толковый словарь русского языка. Под ред. Д. Н. Ушакова …

Антананариву и Окрестности

Будем называть текстом T строку из n символов t1 . . . tn, а каждое окончание текста ti

. . . tn — его суффиксом.

Суффиксное дерево (ST) — это способ представления текста. Неформально говоря, чтобы построить

ST для текста T = t1 . . . tn, нужно приписать специальный символ $ в конец текста, взять все n + 1

суффиксов, подвесить их за начала и склеить все ветки, идущие по одинаковым буквам. В каждом листе записывается номер суффикса, заканчивающегося в этом листе. Номером суффикса является индекс его начала в тексте T. По сути суффиксное дерево – бор для суффиксов

Заметим, что ни один суффикс в ST не может полностью лежать в другом суффиксе, поскольку они

заканчиваются специальным символом $. Таким образом, листьев в ST всегда будет n + 1 для строки

t1 . . . tn, то есть столько же, сколько суффиксов. Но общее число вершин в суффиксном дереве квадратично. Разберемся теперь, как хранить суффиксное дерево, используя линейную память. Для этого оставим в ST только вершины разветвления, то есть имеющие не менее двух детей. Вместо строки для ребра будем хранить ссылку на сегмент текста T[i..j]. В таком виде суффиксное дерево называется сжатым.

 

Заметим, что, так как теперь каждая из внутренних вершин является вершиной разветвления, то она

добавляет к своему поддереву как минимум один лист. Листьев же в ST всего n + 1 для строки t1 . . . tn, поэтому внутренних вершин может быть в диапазоне 1 . . . n.

Таким образом, всего вершин и ребер в сжатом суффиксном дереве будет линейное число, значит онобудет занимать линейную память

Наивный кубический алгоритм

On-line подход

Этот подход основан на том, что данные на вход алгоритму подаются частями, будь то текст или

какие-то запросы.

Алгоритм, использующий on-line подход, читает последовательно поступающие данные

и получает готовое решение на каждом шаге.

Рассмотрим теперь on-line подход для задачи построения суффиксного дерева. Для каждого суффикса

его дополнение до исходного текста T = t1 . . . tn будем называть префиксом, то есть префикс — любое начало текста t1 . . . ti. Будем строить ST не только для всего текста, но последовательно для всех егопрефиксов:

0. Строим суффиксное дерево для t1.

1. Расширяем его до дерева для t1t2.

. . .

n − 1. Расширяем дерево для t1 . . . tn−1 до дерева для t1 . . . tn.

n. Расширяем дерево для t1 . . . tn до дерева для t1 . . . tn$.

Каждый шаг этого списка будем называть фазой алгоритма

 

 

 

Вернемся к примеру с «Войной и миром». Представим, что нам не будет дан сразу весь роман, а будут

даваться по очереди первый, второй и третий тома. Тогда можно построить суффиксное дерево сначала

по первому тому, потом достроить его для двух томов и, наконец, для всего романа.

Неявные суффиксные деревья

Неявное суффиксное дерево (IST) — это суффиксное дерево для текста без $ на конце. Некоторые

суффиксы текста в нем заканчиваются не в листьях, и их номер нигде не хранится.

На рисунке 6 видно, что в явном суффиксном дереве добавилось несколько веток. Это объясняется тем,

что к строке xabxa добавляется не встречавшийся ранее специальный символ $. В результате, для каждого

суффикса происходит либо ответвление с возникновением новой ветки, либо продление символом $.

Фаза = последовательность продлений

Рассмотрим фазу i. В ней мы перестраиваем IST для t1 . . . ti в IST для t1 . . . titi+1. Для каждого j

от 1 до i находим в суффиксном дереве конец суффикса tj . . . ti

. Далее продляем его буквой ti+1, если

необходимо.

Например, рассмотрим фазу на рисунке 7. Надо найти концы суффиксов строки axabx, для этого про-

сто по очереди будем читать их от корня суффиксного дерева. Читаем первый суффикс axabx, приходим

в лист 1, продляем его, дальше читаем суффикс xabx, приходим в лист 2, продляем, и так далее для всех

суффиксов. Но ситуации могут отличаться, как, например, для суффикса x, когда, прочитав его, остаемся

на ребре. В этом случае создаем новую ветку и лист 5.

Всего может быть три типа продлений. Рассмотрим возможные варианты.

1. Продление листа.

Эта ситуация возникает, когда, прочитав суффикс tj .

. . ti

, мы пришли в лист суффиксного дерева.

Тогда «удлиняем» ребро, ведущее в лист, добавляя к строке, соответствующей ребру, новую букву

ti+1.

2. Ответвление буквы.

Прочитав суффикс tj . . . ti

, мы могли остановиться не в листе, а во внутренней вершине или даже

на каком-то ребре.

(a) В случае, когда остановились во внутренней вершине v и из нее нет исходящего ребра по букве

ti+1, добавляем новое ребро из v в новый лист и записывает на ребре букву ti+1.

(b) Но мы могли остановиться на ребре, потому что ребру соответствует сегмент текста T[k..m] =

= tk . . . tm, а не одна буква. Этот случай изображен на рисунке 9.

Допустим, мы прочитали на ребре только часть текста tk . . . ts, которая совпадает с подсуффик-

сом нашего суффикса tj . . . ti

, где ts = ti. Тогда если ts+1 =6 ti+1, разобьем новой внутренней

вершиной v это ребро на два, соответствующие строкам T[k..s] и T[s + 1..m]. Затем создадим

новое ребро с буквой ti+1 из вершины v в новый лист, как в случае 2(a).

 

3. Пустое правило.

Если, прочитав суффикс tj . . . ti, мы остановились во внутренней вершине или на ребре (как в случае 2), но дальше уже есть буква ti+1, не создаем ничего нового.

⇐ Предыдущая78910111213141516Следующая ⇒



2:31 18.12.2010

Алгоритм Укконена на пальцах

Попытаюсь создать очень детское и понятное объяснение (действительно отчётливое понимание алгоритма в не видел ни кого). Инструменты: моя геливая ручка непонятного цвета, линейка, бумажка, сканер. Преполагается что мы знаете что такое суффиксное дерево (уж это не так сложно), вы пытались понять его построение, и у вас нет больших проблем с воображением.

Антананариву, Мадагаскар — точное время

Итак:

Предположим что у нас есть какая-то текстовая строка. S,E — начало и конец нашей строки. Посмотрим на самую длинную ветку нашего суффикного дерева. Схематично её можно изобразить так:

Теперь представим другие ветки нашего дерева. Допустим мы отрезали нашего текста первый символ. В этом случае на дереве мы получим точно такую же ветку, но более короткую (более короткое начало). Поскольку составляя дерево мы всегда отрезаем этот символ, то обе такие ветки есть в нашем дереве:

и обе эти ветки не отличаются ничем кроме длины. У веток разумеется может быть похожий начальный отрезок, в таком случае разветвление может быть не в корне дерева, а чуть дальше.

Теперь появляется такое понятие, как суффиксная связь. В суффиксные связи, связывают все похожие ветки дерева.

В нашем примере суффиксная связь первой ветки указывает на более короткую копию.

Cуффиксная связь второй ветки указывает на следущую ещё более короткую копию:

Вершины 1 и 2 стоят на разном расстоянии от корня. Если суффиксная связь связывает две вершины, то глубина этих вершин всегда отличается только на один символ (это думаю очевидно).

Теперь Алгоритм Укконена. Суть его в том что наш тектовой отрезок растёт, а вместе в ним растёт суффиксное дерево, которое мы имеем. Наша строка S, E вырастает на один символ.Для того чтобы обновить дерево, достаточно просто наложить на неё новую более длинную строку.

От этого наложения измениться одна из веток дерева, а это изменение мы сможем раскопировать по всему дереву, используя наши суффиксные связи.

Теперь представим что может происходить в тот момент, когда ты складываем два текстовых отрезка:

Условно возможны две ситуации. Либо наши отрезки одинаковые (не считая разной длины), тогда ничего не меняется. Либо один из символов различается, в результате чего создаётся развилка.

Теперь представим наше дерево. Если мы добавили новый символ. То все концы у дереве вырастут на один символ. Кроме того на кончиках дерева могут появиться новые развилки, но эти развилки всегда будут небольшие, и всегда будут появляться только у самых кончиков дерева (потому что все предыдущие символы мы не меняли).

Суть (и вся красота) Алгоритма Укконена, которая отличает его от всех похожих алгоритмов, состоит в том — что добавляя новый символ к строке, мы выращиваем наше дерево. А для этого он всего лишь проверяем в нём возможность возникновения новых развилок, которую создаёт новый символ строки (больше делать ему ничего не надо). Простыми словами: если мы добавляем символ, то алгоритм берёт этот (и только этот) символ и просто делает одно сравнение (в одном только месте). Сравнивает его c тем местом где может появиться первая развилка. Больше он не делает ничего. Если новый символ создаёт развилку, то она появляется, затем таким же образом проверяются все копии этого места, для чего достаточно пробежать по суффиксным связям от того места где появилась первая развилка.

Создание новых суффиксных связей: поскольку все копии вновь появившейся развилки, будут абсолютно одинаковыми, по пути все вновь созданные развилки будут связанны между собой новой суффиксной связью.

Заключение

Посидев некоторое время я обнаружил, что не могу быстро придумать, компактный и наглядный пример, на котором можно было бы расписать все ньюансы работы алгоритма, по шагам (точнее такую строку, которая была бы небольшой, но на которой возникают все события необходимые для объяснения). Поэтому продолжение рассказа я пока отложу. Прилагается мой старый исходник без, переделок, из которого вырезано всё лишнее:

[ukk-ref1-lite.cpp]

up. файл устарел. попозже выложу новый, предельно понятный исходник

Алгоритм построения дерева

  1. Символы исходного алфавита образуют список свободных узлов. Каждый узел имеет вес, равный количеству вхождений символа в исходное сообщение.
  2. В списке выбираются два свободных узла с наименьшими весами.
  3. Создается их узел «родитель» с весом, равным сумме их весов, он соединяется с «детьми» дугами.
  4. Одной дуге, выходящей из «родителя» ставится в соответствии «1» бит, другой – «0».
  5. «Родитель» добавляется в список свободных узлов, а двое «детей» удаляются из списка.
  6. Шаги 2-6 повторяются до тех пор, пока в списке свободных узлов не останется.

Пример: построить дерево Хаффмана и найти префиксные коды для сообщения: «КОЛ_ОКОЛО_КОЛОКОЛА»

Решение:

· Составим таблицу частот вхождения символов

· Построим дерево Хаффмана

Блочное кодирование по методу Хаффмана формирует коды для буквосочетаний, составленных из m символов исходного алфавита.

Буквосочетания можно рассматривать как новый, расширенный алфавит объемом

K=Nm , где

N – объем исходного алфавита;

M – число символов в буквосочетании.

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

 

Рассчитаем коэффициент сжатия сообщения.

Пример 3.

Авиабилеты Найроби — Антананариву

Вычислили объем сообщения «КОЛ ОКОЛО КОЛОКОЛА» при использовании кодировок ASCII (Vascii =144 бита) и Unicode (Vunicode = 288 бит). Выше построили код Хаффмана для этой же фразы, на основании которого оценили объем сообщения Vхаффмана=39 бит.

В результате мы получаем коэффициент сжатия равный 144/39 = 3,7 для кодировки ASCII и 288/39 =7,4 для кодировки Unicode.

Метод RLE

В основу алгоритмов RLE (Run-Length Encoding – кодирование путем учета числа повторений) положен принцип выявления повторяющихся последовательностей данных и замены их простой структурой: повторяющийся фрагмент и коэффициент повторения.

Рассмотрим идею сжатия методом RLE. Во входной последовательности:

1. все повторяющиеся цепочки байтов заменяются на фрагменты {управляющий байт, повторяющийся байт}, причем управляющий байт в десятичной системе счисления должен иметь значение 128 + число повторений байта. Это означает, что старший бит управляющего байта для цепочки повторяющихся байтов всегда равен 1.

2. все неповторяющиеся цепочки байтов заменяются на фрагменты {управляющий байт, цепочка неповторяющихся байтов}, причем управляющий в десятичной системе счисления должен иметь значение 0+ длина цепочки. Это означат, что старший бит управляющего байта для цепочки неповторяющихся байтов всегда равен 0.

Замечание. В обоих случаях длина обрабатываем фрагмента не может превосходить 127 байт.

 

Пример 4. Упакуем методом RLE следующую последовательность из 14-ти байтов:

11111111 11111111 11111111 11111111 11111111 11110000 00001111 11000011 10101010 10101010 10101010 10101010 10101010 10101010

В начале последовательности 5 раз повторяется байт 11111111. Чтобы закодировать эти 5-ть байтов, запишем вначале управляющий байт 10000101, а затем сам повторяющийся байт 11111111. Рассмотрим как получился управляющийся байт: к значению 128 мы прибавили число повторений байта 5, получили 13310=100001012.

Далее идут 3 разных байта. Чтобы их закодировать, мы записываем управляющий байт 00000011 (112=310), а затем эти неповторяющиеся байты.

Далее в последовательности 7 раз идет байт 10101010. Чтобы закодировать эти 7 байтов, мы записываем управляющий байт 10000111 (128+7=13510=10001112), а затем повторяющийся байт 10101010.

В результате применения метода RLE мы получаем последовательность из 8-ми байтов: 10000101 11111111 00000011 11110000 00001111 11000011 10000111 10101010.

Таким образом, коэффициент сжатия 14/8=1,75.

Схема распаковки:

1. Если во входной (сжатой) последовательности встречается управляющий байт с единицей в старшем бите, то следующий за ним байт данный надо записать в выходную последовательность столько раз, сколько указано в оставшихся 7-ми битах управляющего байта.

2. Если во входной (сжатой) последовательности управляющий байт с нулем в старшем бите, то в выходную последовательность нужно поместить столько следующих за управляющим байтов входной последовательности, сколько указано в оставшихся 7-ми битах управляющего байта.

Пример 5. Распакуем сжатую последовательность данных методом RLE:

00000010 00001111 11110000 10000110 11000011 00000011 00001111 00111100 01010101.

Первый байт данной последовательности управляющий 000000010, начинается с 0. Следовательно, следующие за ним 102=210 байта помещаются в выходную последовательность.

Замечание.

Будем зачеркивать обработанные байты.

00000010 00001111 11110000 10000110 11000011 00000011 00001111 00111100 01010101

Следующий управляющий байт 10000110 начинается с 1. Следовательно, следующий за ним байт нужно поместить в выходную последовательность 1102=610 раз.

00000010 00001111 11110000 10000110 11000011 00000011 00001111 00111100 01010101

Следующий управляющий байт 00000011 начинается с 0. Следовательно, следующие за ним 112=310 байта нужно поместить в выходную последовательность.

Таким образом, все входные данные мы обработали. А распакованная последовательность байтов выглядит следующим образом:

00001111 11110000 11000011 11000011 11000011 11000011 11000011 11000011 00001111 00111100 01010101

 

Наилучшими объектами для данного алгоритма являются графические данные, в которых встречаются большие одноцветные участки. Различные реализации данного метода используются в графических форматах PCX, BMP и факсимильной передаче информации. Для текстовых данных данный метод неэффективен.

 

 

Предыдущая891011121314151617181920212223Следующая


Дата добавления: 2015-11-10; просмотров: 770;


ПОСМОТРЕТЬ ЕЩЕ:

Добавить комментарий

Закрыть меню