Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Лаб. 2 ТАЯК

.docx
Скачиваний:
0
Добавлен:
25.01.2026
Размер:
158.43 Кб
Скачать

Лабораторная работа №2

Конечные детерминированные автоматы. Преобразование недетерминированного конечного автомата к детерминированному

using System;

using System.Collections.Generic;

using System.IO;

using System.Linq;

using System.Text.RegularExpressions;

class Program

{

class Nfa

{

// Правила перехода (qN: (C: List<<q|f>M>))

public Dictionary<string, Dictionary<char, List<string>>> transitions = new();

// Множество финальных состояний

public HashSet<string> finals = new();

// Множество всех встреченных состояний

public HashSet<string> states = new();

// Множество символов, используемых в переходах

public HashSet<char> alphabet = new();

// Начальное состояние

public string start = "q0";

// Занесение правил перехода, финальных и всех встреченных состояний, а так же символов

public void AddTransition(string src, char sym, string dest)

{

if (!transitions.ContainsKey(src)) transitions[src] = new();

if (!transitions[src].ContainsKey(sym)) transitions[src][sym] = new();

transitions[src][sym].Add(dest);

states.Add(src);

states.Add(dest);

if (dest.StartsWith("f")) finals.Add(dest);

alphabet.Add(sym);

}

public bool IsDeterministic(out List<(string src, char sym, List<string> dests)> nondetRules)

{

nondetRules = new();

foreach (var kv in transitions)

{

string s = kv.Key;

foreach (var symK in kv.Value)

{

var dests = symK.Value;

if (dests.Count > 1)

nondetRules.Add((s, symK.Key, new List<string>(dests)));

}

}

return nondetRules.Count == 0;

}

public bool AcceptsDeterministic(string input)

{

string cur = start;

foreach (char c in input)

{

if (!transitions.TryGetValue(cur, out var map) || !map.TryGetValue(c, out var dests) || dests.Count == 0)

return false;

cur = dests[0];

}

return cur.StartsWith("f");

}

}

class Dfa

{

public Dictionary<int, Dictionary<char, int>> transitions = new();

public HashSet<int> finals = new();

public HashSet<int> states = new();

public HashSet<char> alphabet = new();

public int start = 0;

public bool Accepts(string input)

{

int cur = start;

foreach (char c in input)

{

if (!transitions.TryGetValue(cur, out var map) || !map.TryGetValue(c, out var dest))

return false;

cur = dest;

}

return finals.Contains(cur);

}

}

static void Main()

{

Console.WriteLine("=== НКА/ДКА анализатор ===");

Console.Write("Путь к файлу с переходами (Enter — пример): ");

string path = Console.ReadLine();

List<string> lines;

if (string.IsNullOrWhiteSpace(path))

{

lines = new()

{

"q0,a=f0",

"q0,a=q1",

"q0,b=q1",

"q1,0=f0",

"q1,0=q1"

};

Console.WriteLine("Используется встроенный пример:");

foreach (var l in lines) Console.WriteLine(l);

}

else

{

if (!File.Exists(path)) { Console.WriteLine("Файл не найден."); return; }

lines = File.ReadAllLines(path).Select(s => s.Trim()).Where(s => s.Length > 0).ToList();

}

var nfa = new Nfa();

// Некорректные строки

var bad = new List<(int, string, string)>();

var pat = new Regex(@"^q(\d+),(.{1})=(f|q)(\d+)$");

for (int i = 0; i < lines.Count; i++)

{

string L = lines[i];

var m = pat.Match(L);

if (!m.Success)

{

bad.Add((i + 1, L, "не соответствует шаблону q<N>,<C>=<q|f><M>"));

continue;

}

// Источник (qN)

string src = "q" + m.Groups[1].Value;

// Символ (C)

char sym = m.Groups[2].Value[0];

// Место назначения (<q|f>M)

string dest = m.Groups[3].Value + m.Groups[4].Value;

nfa.AddTransition(src, sym, dest);

}

if (bad.Count > 0)

{

Console.WriteLine("\nОшибка в файле:");

foreach (var e in bad)

Console.WriteLine($" строка {e.Item1}: {e.Item2} -> {e.Item3}");

return;

}

nfa.states.Add(nfa.start);

Console.WriteLine("\n=== Информация ===");

Console.WriteLine("Состояния: " + string.Join(", ", nfa.states.OrderBy(x => x)));

Console.WriteLine("Начальное: " + nfa.start);

Console.WriteLine("Конечные: " + (nfa.finals.Count == 0 ? "(нет)" : string.Join(", ", nfa.finals)));

Console.WriteLine("Алфавит: " + (nfa.alphabet.Count == 0 ? "(пусто)" : string.Join(" ", nfa.alphabet.Select(c => $"'{c}'"))));

// Поиск достижимых

var reachable = new HashSet<string>();

void Dfs(string s)

{

if (reachable.Contains(s)) return;

reachable.Add(s);

if (!nfa.transitions.TryGetValue(s, out var map)) return;

foreach (var kv in map)

foreach (var d in kv.Value)

Dfs(d);

}

Dfs(nfa.start);

// Недостижимые: состояния\достжимые

var unreachable = nfa.states.Except(reachable).ToList();

// Висячие: вершины, которые не являются источниками

var dangling = nfa.states.Where(s => !nfa.transitions.ContainsKey(s)).ToList();

//var isolated = nfa.states.Where(s =>

// (!nfa.transitions.ContainsKey(s) || nfa.transitions[s].Count == 0) &&

// !nfa.transitions.Values.Any(map => map.Values.Any(list => list.Contains(s))) &&

// s != nfa.start).ToList();

if (unreachable.Count > 0)

Console.WriteLine("Недостижимые: " + string.Join(", ", unreachable));

if (dangling.Count > 0)

Console.WriteLine("Висячие вершины: " + string.Join(", ", dangling));

//if (isolated.Count > 0)

// Console.WriteLine("Изолированные вершины: " + string.Join(", ", isolated));

Console.WriteLine("\nПереходы:");

foreach (var src in nfa.transitions.OrderBy(k => k.Key))

foreach (var kv in src.Value)

foreach (var d in kv.Value)

Console.WriteLine($"{src.Key},{kv.Key}={d}");

bool isDet = nfa.IsDeterministic(out var nondet);

Console.WriteLine(isDet ? "\nАвтомат детерминирован." : "\nАвтомат НЕДЕТЕРМИНИРОВАН.");

if (!isDet)

{

Console.WriteLine("Недетерминированные переходы:");

foreach (var n in nondet)

Console.WriteLine($"{n.src},{n.sym} -> {string.Join(", ", n.dests)}");

Console.WriteLine("\n=== Детерминизация ===");

var (dfa, map) = DeterminizeWithMapping(nfa);

Console.WriteLine("Состояния ДКА:");

foreach (var kv in map)

{

string label = "{" + string.Join(",", kv.Value) + "}";

string mark = kv.Value.Any(s => s.StartsWith("f")) ? " [final]" : "";

Console.WriteLine($" q{kv.Key} => {label}{mark}");

}

Console.WriteLine("\nПереходы ДКА:");

foreach (var src in dfa.transitions.OrderBy(k => k.Key))

foreach (var kv in src.Value)

Console.WriteLine($" q{src.Key},{kv.Key}=q{kv.Value}");

Console.WriteLine($"\nНачальное: q{dfa.start}");

Console.WriteLine($"Финальные: {(dfa.finals.Count == 0 ? "(нет)" : string.Join(", ", dfa.finals.Select(i => "q" + i)))}");

WriteDotNfa(nfa, "nfa.dot");

WriteDotDfa(dfa, "dfa.dot", map);

Console.WriteLine("\nСозданы файлы nfa.dot и dfa.dot.");

Console.WriteLine("\n=== Проверка строк (Enter — завершить) ===");

while (true)

{

Console.Write("Строка: ");

string input = Console.ReadLine() ?? "";

if (string.IsNullOrEmpty(input)) break;

bool accept = dfa.Accepts(input);

Console.WriteLine(accept ? " допускается" : " НЕ допускается");

}

}

else

{

WriteDotNfa(nfa, "nfa.dot");

Console.WriteLine("\nСоздан файл nfa.dot");

Console.WriteLine("\n=== Проверка строк (Enter — завершить) ===");

while (true)

{

Console.Write("Строка: ");

string input = Console.ReadLine() ?? "";

if (string.IsNullOrEmpty(input)) break;

bool accept = nfa.AcceptsDeterministic(input);

Console.WriteLine(accept ? " допускается" : " НЕ допускается");

}

}

}

static (Dfa, Dictionary<int, HashSet<string>>) DeterminizeWithMapping(Nfa nfa)

{

var dfa = new Dfa { alphabet = new HashSet<char>(nfa.alphabet) };

var setToId = new Dictionary<string, int>();

var idToSet = new Dictionary<int, HashSet<string>>();

int nextId = 0;

var startSet = new HashSet<string> { nfa.start };

string startKey = string.Join(",", startSet.OrderBy(s => s));

setToId[startKey] = nextId;

idToSet[nextId] = startSet;

dfa.states.Add(nextId);

dfa.start = nextId;

nextId++;

var queue = new Queue<int>();

queue.Enqueue(dfa.start);

while (queue.Count > 0)

{

int curId = queue.Dequeue();

var curSet = idToSet[curId];

if (curSet.Any(s => s.StartsWith("f"))) dfa.finals.Add(curId);

foreach (char sym in dfa.alphabet)

{

var destSet = new HashSet<string>();

foreach (var s in curSet)

if (nfa.transitions.TryGetValue(s, out var map) && map.TryGetValue(sym, out var dests))

foreach (var d in dests) destSet.Add(d);

if (destSet.Count == 0) continue;

string key = string.Join(",", destSet.OrderBy(s => s));

if (!setToId.ContainsKey(key))

{

setToId[key] = nextId;

idToSet[nextId] = destSet;

dfa.states.Add(nextId);

queue.Enqueue(nextId);

nextId++;

}

int destId = setToId[key];

if (!dfa.transitions.ContainsKey(curId)) dfa.transitions[curId] = new();

dfa.transitions[curId][sym] = destId;

}

}

return (dfa, idToSet);

}

static void WriteDotNfa(Nfa nfa, string filename)

{

using var w = new StreamWriter(filename);

w.WriteLine("digraph NFA { rankdir=LR;");

foreach (var s in nfa.states)

{

string shape = s.StartsWith("f") ? "square" : "circle";

w.WriteLine($" {s} [shape={shape},label=\"{s}\"];");

}

w.WriteLine($" start [shape=point]; start -> {nfa.start};");

foreach (var src in nfa.transitions)

foreach (var kv in src.Value)

foreach (var d in kv.Value)

w.WriteLine($" {src.Key} -> {d} [label=\"{kv.Key}\"];");

w.WriteLine("}");

}

static void WriteDotDfa(Dfa dfa, string filename, Dictionary<int, HashSet<string>> map)

{

using var w = new StreamWriter(filename);

w.WriteLine("digraph DFA { rankdir=LR;");

foreach (var s in dfa.states)

{

string label = "{" + string.Join(",", map[s]) + "}";

string shape = dfa.finals.Contains(s) ? "square" : "circle";

w.WriteLine($" q{s} [shape={shape},label=\"q{s}\\n{label}\"];");

}

w.WriteLine($" start [shape=point]; start -> q{dfa.start};");

foreach (var src in dfa.transitions)

foreach (var kv in src.Value)

w.WriteLine($" q{src.Key} -> q{kv.Value} [label=\"{kv.Key}\"];");

w.WriteLine("}");

}

}

Соседние файлы в предмете Теория алгоритмических языков и компиляторов