Программа курса:
Разбор задачи: Разбор булева выражения
Предложенный нами код:
def evaluateBooleanExpression(expression: str) -> bool:
stack = []
for c in expression:
if c == ')':
cache = []
while stack[-1] != '(':
cache.append(stack.pop())
stack.pop()
cur = stack.pop()
stack.append(all(cache) if cur == '&' else any(cache) if cur == '|' else not cache.pop())
elif c != ',':
stack.append(True if c == 't' else False if c == 'f' else c)
return stack.pop() Это решение использует стек для эффективной обработки выражений. Стек помогает отслеживать операторы и операнды, а также сохранять промежуточные результаты вычислений. Рассмотрим код пошагово:
Инициализация стека:
stack = []Стек используется для хранения промежуточных значений и операторов. В нем будет храниться всё: булевы значения (
True,False), операторы (&,|,!), и части выражений, пока они не будут обработаны.Цикл по всем символам выражения:
for c in expression:Перебираются все символы в строке
expression. Каждый символ может быть либо частью операнда (например,tилиf), либо оператором (например,&,|,!), либо символом скобки, которые помогают разделить выражение на подвыражения.Обработка закрывающей скобки
)(обработка подвыражений):if c == ')': cache = [] while stack[-1] != '(': cache.append(stack.pop()) stack.pop() cur = stack.pop() stack.append(all(cache) if cur == '&' else any(cache) if cur == '|' else not cache.pop())Когда встречается символ
), это сигнал о завершении подвыражения. Внутри скобок может быть несколько операндов, разделенных операторами.- Мы начинаем с того, что создаем временный список
cache, в котором будут собираться значения до открытия скобки. - Из стека вытягиваем элементы, пока не достигнем открывающей скобки
(, которая обозначает начало подвыражения. - После этого из стека извлекаем оператор (
&,|, или!). - В зависимости от оператора выполняется соответствующая операция:
- Если оператор
&, то нужно вычислить логическое И для всех значений вcache. Это реализуется с помощьюall(cache). - Если оператор
|, то вычисляем логическое ИЛИ для значений вcacheс помощьюany(cache). - Если оператор
!, то вычисляется логическое НЕ от последнего элемента вcacheс помощьюnot cache.pop().
- Если оператор
- После выполнения операции результат помещается обратно в стек.
- Мы начинаем с того, что создаем временный список
Обработка остальных символов (операнды и операторы):
elif c != ',': stack.append(True if c == 't' else False if c == 'f' else c)Если символ — это не запятая (которая служит для разделения операндов внутри выражений), то это либо булевое значение, либо оператор.
- Если это
t, то добавляется значениеTrueв стек. - Если это
f, то добавляется значениеFalseв стек. - Если это оператор (например,
&,|, или!), он просто добавляется в стек как символ.
- Если это
Возврат результата:
return stack.pop()После того как все символы были обработаны, в стеке должен остаться только один элемент, который является результатом вычисления всего выражения. Мы его извлекаем и возвращаем.
Пример выполнения:
Пример 1:
expression = "&(|(f))"
- Первый символ
&добавляется в стек. - Следующий символ
(— это открывающая скобка, поэтому она просто игнорируется (или может быть использована как маркер начала нового выражения). - Символ
|добавляется в стек. - Затем идет
(, открывающая скобка для нового подвыражения. - Символ
fдобавляется в стек (будет интерпретироваться какFalse). - Закрывается скобка
), которая означает завершение подвыражения. Мы выполняем операцию|для элементов в стеке, результатом будетFalse. - Дальше идет оператор
&, который выполняет операцию И для всех элементов стека. Результат будетFalse.
Пример 2:
expression = "|(f,f,f,t)"
- Первый символ
|добавляется в стек. - Идет символ
(, который открывает подвыражение. - Символы
f, f, f, tдобавляются в стек как значенияFalse,False,False,True. - Закрывается скобка
), что означает выполнение операции|для элементов в стеке. Результат будетTrue, так как одно из значений — этоTrue.