Иногда возникает проблема проверки корректности скобочной структуры. Рассмотрим подробно эту проблему.
Пусть в строке хранится выражение, содержащее скобки: ‘(’ и ’)’. Для понятности определения корректности скобочной структуры рассмотрим примеры:
( ( ) ) – скобочная структура корректна ( ( ) – скобочная структура не корректна ( ) ) – скобочная структура не корректна
Из рассмотренных примеров можно выдвинуть гипотезу.
Гипотеза: «Скобочная структура корректна когда количество открывающих скобок ‘(’ равно количеству закрывающих ‘)’»
Но рассмотрим контрпример: ) ( - скобочная структура не корректна. Но по нашей гипотезе данная скобочная структура будет считаться корректной. В данном случае количество открывающих скобок равно количеству закрывающих, но закрывающая скобка идет раньше, чем открывающая. Из этих утверждений сформулируем правило: «Скобочная структура корректна тогда и только тогда, когда количество открывающих скобок ‘(’ равно количеству закрывающих ‘)’ и нет такого момента времени (при проверке скобок слева направо по одной) когда количество закрывающих скобок больше чем открывающих».
Заведем переменную Rang – числовая характеристика корректности скобочной структуры.
В процессе проверки если встречаем ‘(’ то увеличиваем rang на 1, если ’)’, то уменьшаем rang на 1.
Тогда правило переформулируется так: «Если в процессе проверки rang не был меньше 0, а в конце проверки rang = 0, то такая скобочная структура корректна»
Алгоритм проверки:
Вот как это будет выглядеть:
var s:string; i,rang:integer; begin writeln('Введите строку'); readln(s); rang:=0; for i:= 1 to length(s)do begin if s[i]='('then inc(rang); if s[i]=')'then dec(rang); if rang<0 then break; end; if rang=0 then writeln('Скобочная структура верна') else writeln('Скобочная структура не верна'); readln; end.
Пусть у нас есть строка содержащая 3 вида скобок:
‘(‘, ‘)’, ’[’ , ’]’, ’{’, ’}’
Использование 3х типов скобок не позволяют создать правильный алгоритм анализа скобочной структуры с использованием Rang. Воспользуемся стеком.
Алгоритм.
Для различного типа скобок можно сформулировать ещё одно важное, но очевидное правило:
Скобочные пары двух или более разных типов не могут иметь пересекающуюся структуру.
Вот пример, демонстрирующий правильность этого утверждения:
[{]} - тут нём две скобочные пары пересекаются, хотя и формируют (независимо друг от друга) верные пары.
При дальнейшем рассмотрении этого правила можно заметить такое следствие: внутри любой пары скобок одного типа может быть только лишь чётное количество скобок другого типа, либо их может вобще не быть. Если это число не чётное, то содержимое этой пары скобок сформировано неправильно.
12345678 ([{})])
Если выбрать первую и пятую или первую и седьмую скобки за пару, то внутри них будет нечётное количество скобок, что говорит о неверности выражения.
Еще один вариант рещения данной задачи:
Пока нам встречаеся последовательность из открывающей и закрывающей скобки одного вида, мы их удаляем. В конце:
а) если удалены все скобочные пары (т.е. длина строки в конце равна 0), то скобочное выражене коректно.
б) не все скобки удалены - значит, скобочное выражение неверно.
Пример:
({[()]})[{}]
Сначала алгоритм находит ():
({[]})[{}]
Потом {}:
({[]})[]
Потом 2 раза []:
({})[] и ({})
Опять {}:
()
И, наконец, (): пустая строка
Скобочное выражение было верным.
Function IsCorrect(Expr : String) : Boolean; Var R : Boolean; Begin Repeat R:=False; If (Pos('()', Expr) > 0) Then Begin Delete(Expr, Pos('()', Expr), 2); R:=True; End; If (Pos('{}', Expr) > 0) Then Begin Delete(Expr, Pos('{}', Expr), 2); R:=True; End; If (Pos('[]', Expr) > 0) Then Begin Delete(Expr, Pos('[]', Expr), 2); R:=True; End; Until R = False; IsCorrect:=Length(Expr) = 0; End;