Існує кілька методів перетворення з кінцевих автоматів у регулярні вирази. Тут я опишу те, що зазвичай викладають у школі, і це дуже наочно. Я вважаю, що це найбільше використовується на практиці. Однак написання алгоритму - не така гарна ідея.
Державний метод видалення
Цей алгоритм стосується обробки графіка автомата і тому не дуже підходить для алгоритмів, оскільки йому потрібні графічні примітиви, такі як ... видалення стану. Я опишу це за допомогою примітивів вищого рівня.
Ключова ідея
Ідея полягає в тому, щоб розглянути регулярні вирази на ребрах, а потім видалити проміжні стани, дотримуючись послідовності міток ребер.
Основний візерунок можна побачити на малюнках нижче. Перший має мітки між які є регулярними виразами e , f , g , h , i, і ми хочемо видалити q .p,q,re,f,g,h,iq
Після вилучення ми складаємо разом (зберігаючи інші ребра між p і r, але це не відображається на цьому):e,f,g,h,ipr
Приклад
Використовуючи той же приклад, що і у відповіді Рафаеля :
ми послідовно видаляємо :q2
а потім :q3
тоді нам ще належить застосувати зірку на вираз від до q 1 . У цьому випадку кінцевий стан також є початковим, тому нам дійсно просто потрібно додати зірку:q1q1
(ab+(b+aa)(ba)∗(a+bb))∗
Алгоритм
L[i,j]
- це зворотне вираження мови від до q j . Спочатку видаляємо всі багатокрайники:qiqj
for i = 1 to n:
for j = 1 to n:
if i == j then:
L[i,j] := ε
else:
L[i,j] := ∅
for a in Σ:
if trans(i, a, j):
L[i,j] := L[i,j] + a
Тепер державне зняття. Припустимо, ми хочемо видалити стан :qk
remove(k):
for i = 1 to n:
for j = 1 to n:
L[i,i] += L[i,k] . star(L[k,k]) . L[k,i]
L[j,j] += L[j,k] . star(L[k,k]) . L[k,j]
L[i,j] += L[i,k] . star(L[k,k]) . L[k,j]
L[j,i] += L[j,k] . star(L[k,k]) . L[k,i]
star(ε)=ε
e.ε=e
∅+e=e
∅.e=∅
∅εqiqkqjqk
Тепер, як користуватися remove(k)
? Не слід видаляти остаточні або початкові стани злегка, інакше ви пропустите частини мови.
for i = 1 to n:
if not(final(i)) and not(initial(i)):
remove(i)
Якщо у вас є лише один кінцевий стан та один початковий стан то остаточним виразом є:qfqs
e := star(L[s,s]) . L[s,f] . star(L[f,s] . star(L[s,s]) . L[s,f] + L[f,f])
Якщо у вас є кілька кінцевих станів (або навіть початкових станів), то немає простого способу їх злиття, крім застосування методу перехідного закриття. Зазвичай це не проблема вручну, але це незручно при написанні алгоритму. Набагато простіше вирішення - перерахувати всі пари та запустити алгоритм на (вже видаленому стані) графіку, щоб отримати всі вирази припустимо, що є єдиним початковим станом, а - єдиним остаточним держава, то роблячи об'єднання всіх .(s,f)es,fsfes,f
Це та факт, що це зміна мов більш динамічно, ніж перший метод, роблять її більш схильною до помилок при програмуванні. Я пропоную використовувати будь-який інший метод.
Мінуси
У цьому алгоритмі дуже багато випадків, наприклад, для вибору, який вузол нам слід видалити, кількість кінцевих станів наприкінці, те, що кінцевий стан може бути початковим, і т.д.
Зауважимо, що тепер, коли алгоритм написаний, це дуже схоже на метод перехідного закриття. Тільки контекст використання інший. Я не рекомендую реалізувати алгоритм, але використовувати метод, щоб зробити це вручну, - це гарна ідея.