You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Delphi计算器中实现运算优先级(PEMDAS)的技术问询

Delphi计算器实现运算优先级(PEMDAS)的可行方案

核心方案:双栈法

用两个栈分别存储操作数和运算符,通过遍历表达式Token,根据运算符优先级决定是入栈还是先执行运算,完美适配你的TStringList存储结构。

处理逻辑

  1. 遍历拆分后的表达式Token列表(比如["5", "+", "2", "*", "6"])
  2. 遇到操作数直接压入操作数栈
  3. 遇到运算符时:
    • 循环检查运算符栈顶的优先级,如果栈顶运算符优先级≥当前运算符,弹出栈顶运算符和两个操作数(注意顺序:后弹出的是左操作数)
    • 计算结果后将结果压回操作数栈
    • 把当前运算符压入运算符栈
  4. 遍历结束后,处理运算符栈中剩余的所有运算符,依次计算直到栈为空
  5. 操作数栈最后剩余的元素就是最终结果

示例流程(5 + 2 * 6)

  1. 压入操作数5 → 操作数栈:[5]
  2. 运算符+入栈 → 运算符栈:[+]
  3. 压入操作数2 → 操作数栈:[5,2]
  4. 运算符*优先级高于栈顶的+,直接入栈 → 运算符栈:[+,*]
  5. 压入操作数6 → 操作数栈:[5,2,6]
  6. 遍历结束,处理剩余运算符:
    • 弹出*,弹出6和2,计算2*6=12,压回操作数栈 → 操作数栈:[5,12]
    • 弹出+,弹出12和5,计算5+12=17,压回操作数栈 → 操作数栈:[17]
  7. 最终结果为17

伪代码实现(适配Delphi TStringList)

// 假设ExpressionTokens是已拆分好的表达式Token列表(操作数、运算符交替)
var
  OperandStack: TStringList; // 模拟操作数栈:Add压栈,Delete(Count-1)弹栈,Last取栈顶
  OperatorStack: TStringList; // 模拟运算符栈
  I: Integer;
  CurrentToken: string;
  Op1, Op2, ResultVal: Double;
  OpTop: string;
begin
  OperandStack := TStringList.Create;
  OperatorStack := TStringList.Create;
  try
    for I := 0 to ExpressionTokens.Count - 1 do
    begin
      CurrentToken := ExpressionTokens[I];
      // 判断是否为操作数(数字)
      if TryStrToDouble(CurrentToken, ResultVal) then
      begin
        OperandStack.Add(CurrentToken);
      end
      // 判断是否为运算符
      else if CurrentToken in ['+', '-', '*', '/', '(', ')'] then
      begin
        if CurrentToken = '(' then
        begin
          // 左括号直接入栈
          OperatorStack.Add(CurrentToken);
        end
        else if CurrentToken = ')' then
        begin
          // 右括号:计算到左括号为止
          while (OperatorStack.Count > 0) and (OperatorStack[OperatorStack.Count-1] <> '(') do
          begin
            OpTop := OperatorStack[OperatorStack.Count-1];
            OperatorStack.Delete(OperatorStack.Count-1);
            
            // 弹出两个操作数(注意顺序:先弹右,后弹左)
            Op2 := StrToDouble(OperandStack[OperandStack.Count-1]);
            OperandStack.Delete(OperandStack.Count-1);
            Op1 := StrToDouble(OperandStack[OperandStack.Count-1]);
            OperandStack.Delete(OperandStack.Count-1);
            
            // 计算并压回结果
            case OpTop of
              '+': ResultVal := Op1 + Op2;
              '-': ResultVal := Op1 - Op2;
              '*': ResultVal := Op1 * Op2;
              '/': if Op2 <> 0 then ResultVal := Op1 / Op2 else raise Exception.Create('除数不能为0');
            end;
            OperandStack.Add(FloatToStr(ResultVal));
          end;
          // 弹出左括号(不参与计算)
          if OperatorStack.Count > 0 then
            OperatorStack.Delete(OperatorStack.Count-1);
        end
        else
        begin
          // 处理普通运算符:优先级判断
          while (OperatorStack.Count > 0) and (GetPriority(OperatorStack[OperatorStack.Count-1]) >= GetPriority(CurrentToken)) do
          begin
            OpTop := OperatorStack[OperatorStack.Count-1];
            OperatorStack.Delete(OperatorStack.Count-1);
            
            Op2 := StrToDouble(OperandStack[OperandStack.Count-1]);
            OperandStack.Delete(OperandStack.Count-1);
            Op1 := StrToDouble(OperandStack[OperandStack.Count-1]);
            OperandStack.Delete(OperandStack.Count-1);
            
            case OpTop of
              '+': ResultVal := Op1 + Op2;
              '-': ResultVal := Op1 - Op2;
              '*': ResultVal := Op1 * Op2;
              '/': if Op2 <> 0 then ResultVal := Op1 / Op2 else raise Exception.Create('除数不能为0');
            end;
            OperandStack.Add(FloatToStr(ResultVal));
          end;
          // 当前运算符入栈
          OperatorStack.Add(CurrentToken);
        end;
      end;
    end;
    
    // 处理剩余的运算符
    while OperatorStack.Count > 0 do
    begin
      OpTop := OperatorStack[OperatorStack.Count-1];
      OperatorStack.Delete(OperatorStack.Count-1);
      
      Op2 := StrToDouble(OperandStack[OperandStack.Count-1]);
      OperandStack.Delete(OperandStack.Count-1);
      Op1 := StrToDouble(OperandStack[OperandStack.Count-1]);
      OperandStack.Delete(OperandStack.Count-1);
      
      case OpTop of
        '+': ResultVal := Op1 + Op2;
        '-': ResultVal := Op1 - Op2;
        '*': ResultVal := Op1 * Op2;
        '/': if Op2 <> 0 then ResultVal := Op1 / Op2 else raise Exception.Create('除数不能为0');
      end;
      OperandStack.Add(FloatToStr(ResultVal));
    end;
    
    // 输出最终结果
    if OperandStack.Count = 1 then
      ShowMessage('计算结果:' + OperandStack[0])
    else
      raise Exception.Create('表达式格式错误');
  finally
    OperandStack.Free;
    OperatorStack.Free;
  end;
end;

// 辅助函数:获取运算符优先级
function GetPriority(const Op: string): Integer;
begin
  if Op in ['*', '/'] then
    Result := 2
  else if Op in ['+', '-'] then
    Result := 1
  else if Op = '(' then
    Result := 0 // 左括号优先级最低,避免提前计算括号内内容
  else
    Result := -1;
end;

关键注意事项

  • 确保表达式已正确拆分为Token(比如"5+2*6"要拆成["5", "+", "2", "*", "6"],可以通过遍历字符拆分实现)
  • 处理除数为0的异常情况,避免程序崩溃
  • 扩展指数运算的话,只需给^或**设置更高的优先级(比如3),并在计算分支中添加指数运算逻辑

内容的提问来源于stack exchange,提问作者nahic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 15:12:06