Двигатели DFA vs NFA: в чем разница в их возможностях и ограничениях?

Я ищу нетехнические объяснение разницы между двигателями DFA и NFA на основе их возможностей и ограничений.

5 ответов


детерминированные конечные автоматы (DFAs) и недетерминированные конечные автоматы (NFAs) имеют точно такие же возможности и ограничения. Разница только в обозначениях удобство.

конечный автомат-это процессор, который имеет состояния и считывает входные данные, каждый входной символ потенциально переводит его в другое состояние. Например, состояние может быть "просто прочитано два Cs подряд"или" я начинаю слово". Они обычно используются для быстрого сканирования текста для поиска шаблонов, таких как как лексическое сканирование исходного кода, чтобы превратить его в токены.

детерминированный конечный автомат находится в одном состоянии за раз, что реализуемо. Недетерминированный конечный автомат может находиться одновременно в нескольких состояниях: например, в языке, где идентификаторы могут начинаться с цифры, может быть состояние "чтение числа" и другое состояние "чтение идентификатора", а NFA может быть в обоих одновременно при чтении чего-то, начинающегося с "123". Какое государство на самом деле применяется будет зависеть от того, столкнулся ли он с чем-то не числовым до конца слова.

теперь мы можем выразить "чтение числа или идентификатора" как само состояние, и внезапно нам не нужен NFA. Если мы выражаем комбинации состояний в NFA как сами государства, у нас есть DFA с гораздо большим количеством состояний, чем NFA, но который делает то же самое.

Это вопрос, который легче читать или писать или заниматься. DFAs легче понять как таковой, но NFAs, как правило, меньше.


вот нетехнический ответ от Microsoft:

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

традиционные двигатели NFA работают так называемые" жадные " алгоритмы выслеживания совпадений, тестирующие все возможные расширения регулярного выражения в определенном порядке и принимающие первое совпадение. Потому что традиционный НФА создает определенное расширение регулярное выражение для совпадения, он может захватить подвыражений и соответствующие обратные ссылки. Однако, поскольку традиционный NFA возвращается, он может посетить точно такое же состояние несколько раз, если состояние получено по разным путям. В результате, он может в худшем случае бегите экспоненциально медленно. Поскольку традиционный NFA принимает первое совпадение, которое он находит, он также может оставить другие (возможно, более длинные) совпадения неоткрытыми.

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

традиционные двигатели NFA предпочитают программисты, потому что они более выразительны, чем двигатели DFA или POSIX NFA. Хотя в худшем случае они могут работать медленно, вы можете направить их на поиск совпадений в линейном или полиномиальном времени, используя шаблоны, которые уменьшают неоднозначность и ограничивают обратное отслеживание.

[http://msdn.microsoft.com/en-us/library/0yzc2yb0.aspx]


простое, нетехническое объяснение, перефразированное из книги Джеффри Фридля Использование Регулярных Выражений.

предостережение:

Edit:


оригинальный ответ:

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

представьте себе строку AAB и регулярное выражение A*AB. Теперь мы шагаем через нашу строку буква письмо.

  1. A:

    • первая ветка: может быть сопоставлена A*.
    • вторая ветвь: может быть сопоставлена, игнорируя A* (допускаются нулевые повторения) и использование второго A в регулярное выражение.
  2. A:

    • первая ветвь: может быть сопоставлена путем расширения A*.
    • вторая ветвь: не может быть сопоставлена B. Вторая ветка неудачи. Но:
    • третья ветвь: можно сопоставить, не расширяя A* и через второй элемент A вместо.
  3. B:

    • первая ветвь: не может быть сопоставлена с расширением A* или перейти в regex для следующий маркер A. Первая ветка терпит неудачу.
    • третья ветвь: смогите быть сопрягано. Ура!

двигатель DFA никогда не возвращается в строку.


An двигатель NFA шагов через выражение token by token и пробует все возможные перестановки в строке, при необходимости отступая. Если он достигает конца регулярного выражения, он объявляет об успехе.

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

  1. A* матч AA. Запомните отступающие позиции 0 (начало строки) и 1.
  2. A: не совпадает. Но у нас есть обратная позиция, в которую мы можем вернуться и попробовать снова. Механизм регулярных выражений отступает на один символ. Теперь A матчи.
  3. B: матчи. Достигнут конец регулярного выражения (с одной отступающей позицией). Ура!


оба NFAs и DFAs являются конечными автоматами, как говорят их имена.

оба могут быть представлены как начальное состояние, состояние успеха (или" accept") (или набор состояний успеха) и таблица состояний с перечислением переходов.

в таблице состояния DFA, каждый <state₀, input> ключ будет переходить к одному и только одному state₁.

в таблице состояния NFA, каждый <state₀, input> перейдут на set государств.

когда вы берете DFA, сбросьте его на это начальное состояние, последовательность входных символов, и вы точно знаете, в каком конечном состоянии он находится и является ли это состоянием успеха или нет.

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

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

Я нахожу объяснение в Регулярные Выражения, Полный Учебник Ян Гойваертс, чтобы быть наиболее полезным. См. страницу 7 этого PDF:

https://www.princeton.edu / ~mlovett / ссылка/регулярные выражения.pdf

среди других пунктов, сделанных на странице 7,существует два вида движков регулярных выражений: движки, направленные на текст, и движки, направленные на регулярное выражение. Джеффри Фридль называет их двигателями DFA и NFA соответственно. ...некоторые очень полезные функции, такие как ленивые кванторы и обратные ссылки, могут быть реализованы только в движках, ориентированных на регулярное выражение.