题目
如何实现一个简单的逻辑表达式求值器
要求实现一个程序,该程序能够接收一个由逻辑运算符(“or”、“and”、“not”)和逻辑值(“true”、“false”)组成的字符串表达式,然后计算并输出这个表达式的结果。
核心思路(函数级)
-
操作符判断 (
is_op): 定义一个函数来判断给定的字符串是否为逻辑操作符(“or”、“and” 或 “not”)。 -
操作符优先级 (
priority): 定义一个函数来确定不同逻辑操作符的优先级,以便于按正确的顺序执行操作。 -
操作符处理 (
process_op): 定义一个函数来执行逻辑操作。根据操作符(“not”、“and” 或 “or”)和操作数(“true” 或 “false”),更新栈顶元素的值。 -
表达式求值 (
evaluate): 定义一个函数来计算整个逻辑表达式的值。使用两个栈(一个用于操作数,一个用于操作符)来处理表达式,并根据操作符的优先级和结合性来计算最终结果。 -
表达式合法性检查 (
check): 定义一个函数来验证逻辑表达式是否符合语法规则,例如,不能以操作符开始或结束,“not” 后面必须跟操作数等。 -
主函数 (
main): 主函数负责读取用户输入的逻辑表达式,将其分割成操作符和操作数的列表,然后调用check函数检查表达式的合法性。如果表达式合法,调用evaluate函数计算并打印结果;如果不合法,打印错误信息。
函数流程
-
main()函数: 程序执行从main函数开始。 -
check(s, cnt): 然后,main函数调用check函数,传入分割后的列表s和计数cnt,以检查表达式的合法性。 -
evaluate(s, cnt): 如果check函数返回True,main函数接着调用evaluate函数来计算逻辑表达式的值。 -
is_op(s[i]): 在evaluate函数内部,对于每个元素s[i],首先调用is_op函数来判断它是否是一个操作符。 -
priority(op): 如果是操作符,evaluate函数会调用priority函数来获取操作符的优先级。 -
process_op(st, op): 在操作符的优先级确定后,如果需要,evaluate函数将调用process_op函数来执行栈顶的操作数和操作符的逻辑运算。 -
循环处理:
evaluate函数中的循环会重复处理输入的表达式,直到所有的操作符都被处理完毕。 -
返回结果: 最终,
evaluate函数返回计算得到的逻辑表达式的值。 -
打印结果:
main函数接收到evaluate函数返回的结果,并将其打印出来。 -
错误处理: 如果
check函数返回False,表示表达式不合法,main函数将打印错误信息。
伪代码
初始化一个名为cnt的变量为0,用于计数输入的逻辑表达式中的元素数量。
定义一个名为is_op的函数,它接受一个字符串参数s。这个函数检查s是否是"or"、"and"或"not"中的任意一个。如果是,函数返回True;否则,返回False。
定义一个名为priority的函数,它接受一个操作符参数op。这个函数根据op是"or"、"and"还是"not",返回相应的优先级值1、2或3。
定义一个名为process_op的函数,它接受一个栈st和一个操作符op作为参数。这个函数执行如下操作:
- 弹出栈st顶部的元素r。
- 如果op是"not",根据r的值("true"或"false"),将相反的值压入栈st。
- 如果op是"and",先弹出栈st顶部的元素l,然后将l与r进行逻辑与操作,将结果压入栈st。
- 如果op是"or",先弹出栈st顶部的元素l,然后将l与r进行逻辑或操作,将结果压入栈st。
定义一个名为evaluate的函数,它接受一个字符串列表s和一个计数器cnt作为参数。这个函数执行如下操作:
- 初始化两个空栈,分别用于存储操作数和操作符。
- 遍历列表s中的每个元素:
- 如果元素是操作符,根据优先级和操作符类型,从操作符栈中弹出相应的操作符,并使用process_op函数进行处理。
- 如果元素不是操作符(即是一个操作数),将它压入操作数栈。
- 当所有元素都被处理后,弹出操作符栈中的剩余操作符,并进行处理,直到栈为空。
- 返回操作数栈顶部的元素,这是逻辑表达式计算的结果。
定义一个名为check的函数,它接受一个字符串列表s和一个计数器cnt作为参数。这个函数检查逻辑表达式的合法性,包括:
- 如果cnt为0,即没有输入任何元素,返回False。
- 检查表达式的第一个元素和最后一个元素,确保它们不是操作符。
- 检查"not"操作符后面是否跟有非法的操作符。
- 如果发现任何非法模式,设置标志变量flag为False并返回。
定义一个名为main的函数,作为程序的入口点:
- 初始化一个空列表s,用于存储分割后的逻辑表达式。
- 读取用户输入的整个逻辑表达式,清除首尾空格,并分割成单词列表,然后更新cnt为列表的长度。
- 调用check函数检查逻辑表达式的合法性。
- 如果表达式合法,调用evaluate函数计算表达式的值,并打印结果。
- 如果表达式不合法,打印"error"。
CODE
cnt = 0
# 定义一个函数,用于判断字符串是否为操作符
def is_op(s):
# 如果s等于"or"、"and"或"not"中的任意一个,那么表达式的结果为True;否则,结果为False。
return s == "or" or s == "and" or s == "not"
# 定义一个函数,用于计算操作符的优先级
def priority(op):
if op == "or":
return 1
if op == "and":
return 2
if op == "not":
return 3
return -1
# 定义一个函数,用于处理操作符
def process_op(st, op):
"""
如果运算符是"not",那么将栈顶元素r与"true"进行比较,如果相等,则将"false"压入栈中;否则将"true"压入栈中。
如果运算符是"and",那么先弹出栈顶元素l,然后将l与r进行比较,如果都为"true",则将"true"压入栈中;否则将"false"压入栈中。
如果运算符是"or",那么先弹出栈顶元素l,然后将l与r进行比较,如果都为"false",则将"false"压入栈中;否则将"true"压入栈中。
栈(stack)主要用于存储逻辑运算的 operands(操作数)
"""
# 栈
r = st.pop()
if op == "not":
st.append("false" if r == "true" else "true")
elif op == "and":
l = st.pop()
st.append("true" if r == "true" and l == "true" else "false")
elif op == "or":
l = st.pop()
st.append("false" if r == "false" and l == "false" else "true")
# 定义一个函数,用于计算表达式的值
def evaluate(s, cnt):
"""
evaluate(s, cnt): 这个函数接受两个参数,s 是一个字符串列表,其中包含了逻辑表达式中的运算符和操作数;cnt 是列表 s 中元素的数量。
将一个字符串s中的运算符和操作数进行优先级计算,最终得到一个计算结果。
遍历字符串s中的每个字符,判断其是否为运算符。如果是运算符,则进行以下操作:
a. 获取当前运算符cur_op。 b. 当op列表不为空,且op列表中的最后一个元素的优先级大于等于cur_op时,弹出op列表中的最后一个元素,并进行计算。 c. 如果cur_op不为"not",则当op列表中的最后一个元素为"not"时,弹出op列表中的最后一个元素,并进行计算。 d. 将cur_op添加到op列表中。
"""
st = []
op = []
for i in range(cnt):
# a. 如果是操作数,就获取当前操作符 cur_op。
if is_op(s[i]):
cur_op = s[i]
"""步骤 b 是一个通用的操作符优先级处理,它适用于所有二元操作符("and" 和 "or")。
步骤 c 是一个特殊情况处理,专门针对 "not" 操作符,因为 "not" 是一个单目操作符,它的处理逻辑与二元操作符不同。
"""
# b. 当操作符栈 op 不为空,并且栈顶操作符的优先级大于等于 cur_op 的优先级时,从 op 栈中弹出操作符,并使用 process_op 函数进行计算。
# 空了表示之前的都完成计算了可以继续引入运算符
while op and priority(op[-1]) >= priority(cur_op):
process_op(st, op.pop())
# c. 如果 cur_op 不是 "not",并且 op 栈不为空且栈顶为 "not",则弹出 "not" 并进行计算。(NOT优先级高)
if cur_op != "not":
while op and op[-1] == "not":
process_op(st, op.pop())
# 其实这里bc可以合并的
# d. 将 cur_op 添加到操作符栈 op 中。
op.append(cur_op)
else:
st.append(s[i])
while op:
process_op(st, op.pop())
return st[0]
# 定义一个函数,用于检查表达式是否合法
def check(s, cnt):
"""
s 是一个字符串列表,代表逻辑表达式中的各个元素
cnt 是列表 s 中元素的数量。
确保:表达式不能以 "or" 或 "and" 开头。
表达式的最后一个元素不能是 "or", "and", 或 "not"。
"not" 操作符后面必须是 "true" 或 "false",而不能是另一个操作符。
"""
# cnt为0的处理
if cnt == 0:
return False
flag = True
# 如果表达式的第一个元素是 "or" 或 "and",或者最后一个元素是 "or", "and", 或 "not",则表达式不合法。在这种情况下,将 flag 设置为 False 并返回。
if (s[0] == "or" or s[0] == "and" or s[cnt - 1] == "or" or s[cnt - 1] == "and") or (
s[cnt - 1] == "not"
):
flag = False
return flag
# 如果遇到 "not" 操作符(s[i] == "not"),则检查其后一个元素(s[i + 1])是否为 "or" 或 "and"。如果是,那么这个表达式是非法的,因为 "not" 后面应该跟一个逻辑值("true" 或 "false"),而不是另一个操作符。在这种情况下,将 flag 设置为 False 并返回。
for i in range(cnt):
if s[i] == "not" and (i + 1 < cnt and (s[i + 1] == "or" or s[i + 1] == "and")):
flag = False
return flag
return flag
# 主函数
def main():
global cnt
s = [] # 使用空列表来存储输入的逻辑表达式
# 一次性读取整个输入表达式
expr = input().strip()
# 分割表达式为单词列表,这里假设输入的逻辑表达式由空格分隔
s = expr.split()
cnt = len(s) # 更新计数器为输入表达式的长度
if check(s, cnt):
print(evaluate(s, cnt))
else:
print("error")
if __name__ == "__main__":
main()
1867

被折叠的 条评论
为什么被折叠?



