Конечные автоматы: состояния, переходы и регулярные языки
Как турникет и лексер принимают решения: детерминированные и недетерминированные автоматы, диаграммы состояний, трассировка входных слов и регулярные языки.
Турникет в метро не помнит, кто вы и сколько раз вы сегодня ездили. Он помнит ровно одно: открыт он сейчас или закрыт. Монетка — переходит в состояние «открыт», проход — возвращается в «закрыт». Всё. И при этом конструкция решает задачу доступа идеально. Конечный автомат — модель систем, которым хватает конечной памяти: турникеты, контроллеры лифтов, парсеры, сетевые протоколы. Это финальная тема курса, и она красиво замыкает всё, что мы уже изучили: состояния и переходы — это граф, условия переходов — логика, а сам автомат — способ определять язык.
Формальная модель: пять штук в скобках#
Детерминированный конечный автомат (ДКА) — пятёрка :
- — конечное множество состояний (для турникета: «закрыт», «открыт»)
- — входной алфавит: символы, которые автомат читает (монетка, проход)
- — функция переходов: из какого состояния и по какому символу — куда идём
- — начальное состояние, здесь автомат живёт до первого символа
- — множество допускающих (принимающих) состояний
Работает автомат так: читает входное слово символ за символом и шагает по переходам. Слово допускается, если после последнего символа автомат оказался в состоянии из . Множество всех допускаемых слов — язык автомата. Никакой памяти, кроме текущего состояния, у автомата нет — в этом и сила модели, и её предел.
Рисуют автомат диаграммой состояний: состояния — кружки, переходы — стрелки с подписями символов, старт отмечают входящей стрелкой, допускающие состояния — двойными кружками. По сути, это ориентированный граф с помеченными рёбрами — техника из основ графов напрямую переносится сюда. Вторая форма записи — таблица переходов: строки-состояния, столбцы-символы, в клетке куда идём; по структуре это матрица переходов.
Первый пример: чётность единиц#
Задача: допускать двоичные слова с чётным числом единиц. Состояний нужно два: («прочитано чётное число единиц») и («нечётное»). Ноль единиц — число чётное, значит старт в , и . Переходы: по 0 состояние не меняется, по 1 — переключается между и .
Трассируем слово : старт в ; символ 1 — идём в ; символ 0 — остаёмся в ; символ 1 — в ; символ 1 — в . Конец слова, автомат в — слово не допускается. Проверка руками: в три единицы — нечётно, верно. Механика железобетонная: состояние просто «помнит» чётность прочитанного, и никакой счётчик не нужен.
| Состояние | по символу 0 | по символу 1 |
|---|---|---|
| (чётное) | ||
| (нечётное) |
- Условие: допускать двоичные слова, в которых никогда не встречаются две единицы подряд.
- Что помнить? Только чем кончилось прочитанное: — «кончилось нулём или пусто», — «кончилось единицей».
- Третья состояние-ловушка — «уже видели 11»: из неё выходов нет, любое продолжение остаётся в ней.
- Переходы: из по 0 — в , по 1 — в ; из по 0 — в , по 1 — в ловушку ; из по любому символу — в .
- Допускающие: и . Трасса слова 10101: — допускается. Слово 1101 после второй единицы уходит в и остаётся там — не допускается.
Проектируем автомат по шагам#
Типовая задача семинара: построить автомат для заданного условия. Алгоритм такой: придумать, какую информацию о прочитанной части слова нужно помнить (это и будут состояния), определить переходы для каждого символа из каждого состояния, пометить допускающие, прогнать несколько тестовых слов. Разберём: допускать слова над алфавитом , которые оканчиваются на .
ДКА против НКА: детерминизм#
В недетерминированном автомате (НКА) переход может вести сразу в несколько состояний, а некоторые переходы разрешено помечать пустым словом (читать символ не нужно). Слово допускается, если существует хотя бы один путь по переходам, приводящий в допускающее состояние. Формально функция переходов превращается в отображение — в множество состояний.
НКА кажется мощнее: он как будто «угадывает» правильную ветку. Теорема Рабина-Скотта утверждает: нет. Любой НКА можно детерминизировать построением ДКА, состояния которого — подмножества состояний НКА (в худшем случае их , но на практике обычно меньше). Оба класса распознают в точности одни и те же языки. НКА удобнее конструировать, ДКА — исполнять: поэтому реальные инструменты хранят НКА-подобные структуры, а исполняют детерминизированную версию.
Мини-пример детерминизации можно устроить в уме. Пусть НКА по символу a из состояния идёт сразу в и . Соответствующий ДКА будет иметь состояние-подмножество и переход — объединение образов. Смотрите, как растёт счёт: два состояния НКА породили до четырёх состояний ДКА; десять — до 1024. Отсюда практический совет: конструируйте НКА, детерминизируйте только те подмножества, которые реально достижимы со старта — обычно их на порядки меньше .
Регулярные языки и где это всё живёт#
Языки, распознаваемые конечными автоматами, называются регулярными. Теорема Клини связывает их с регулярными выражениями: классы совпадают. Каждое регулярное выражение можно скомпилировать в НКА (алгоритм Томпсона), детерминизировать, минимизировать — и исполнять с линейной скоростью. Именно так работает grep, движки регулярных выражений и лексический анализатор компилятора: автомат читает исходный код посимвольно и нарезает его на токены.
Предел модели стоит знать: память автомата конечна, поэтому «посчитать» он не может ничего. Язык «равное число открывающих и закрывающих скобок» автомату не по силам — нужен счётчик неограниченной длины (для этого существуют стековые автоматы, на которых построены парсеры). Практическое следствие: валидацию форматов (телефоны, почтовые индексы) делают автоматами, а разбор вложенных конструкций — нет.
- Состояния — это вся память; проектирование начинается с вопроса «что помнить о прочитанном».
- ДКА: из каждого состояния по каждому символу ровно один переход — не хватает варианта, добавляйте ловушку.
- НКА: переходы в множества и -шаги; слово допускается, если существует хотя бы один успешный путь.
- Детерминизация растит состояния до , минимизация сжимает обратно.
- Считать автомат не умеет: вложенные скобки и произвольные палиндромы — не его язык.
Автомат с состояниями допускает чётное число единиц. Что он скажет о слове 1100?
Почему НКА не мощнее ДКА?
Частые вопросы
Как придумать состояния для автомата в задаче?
Спросите себя: что нужно помнить о прочитанной части слова, чтобы в любой момент решить, допускать ли его? Ответы вида «кончается на a», «чётное число единиц», «уже видели образец» — и есть состояния. Лишние состояния потом убирает минимизация.
Что такое минимальный ДКА?
ДКА с наименьшим числом состояний среди всех автоматов, распознающих тот же язык. Он единственный с точностью до переименования состояний, а строится алгоритмом: сначала удаляются недостижимые состояния, затем сливаются эквивалентные — те, у которых одинаковое поведение на всех продолжениях входа.
Чем конечный автомат отличается от машины Тьюринга?
Памятью. У автомата память — текущее состояние, их конечное число. Машина Тьюринга имеет ленту неограниченной длины и может хранить сколько угодно информации; на ней реализуемы любые алгоритмы. Автоматы — частный, сильно ограниченный случай: быстрые, но не всесильные.
Где в реальном коде я встречу конечные автоматы?
Лексеры и парсеры, валидация ввода, сетевые протоколы (TCP имеет диаграмму состояний из RFC), игровые боты и AI-поведение NPC, движки регулярных выражений, UI-машины состояний в интерфейсах. Паттерн State в объектно-ориентированном проектировании — прямой родственник этого материала.
Готовитесь к контрольной?
Чеклист тем по «Дискретка»: что вы уже умеете, что повторить и в каком порядке.
Открыть чеклист предмета →
Проверьте себя в бою
Босс-экзамен по «Дискретка»: квизы всех уроков плюс бесконечный поток сгенерированных задач. Каждая попытка — новый расклад.
Начать босс-экзамен →