当前位置: 首页 > article >正文

利用栈实现中缀表达式的简单计算

表达式计算

实现简单的中缀表达式计算:

  1. 实现对于输入的中缀表达式字符串进行计算
  2. 对于输入表达式错误能够识别并输出表达式错误
    • 括号不匹配
    • 计算结束后,运算符栈里还有元素
    • 遇到除数字和运算符和括号的字符之外的其他字符

解决步骤:

  1. 实现MyStack类,使用泛型,即在创建该类时传入数据类型,确定成员变量顺序数组的数据类型,写栈的基本方法:判满、判空、入栈、弹栈、返回栈顶元素

  2. 构造两个栈:一个存储运算符的栈operator(char)(包括+ - * / ),再构造一个存储操作数的栈operand(double)

    1. 对于operator,栈里面只存储运算符,对于入栈有运算符优先级比较,具体有4个规则

      • ‘*’ ‘/’ 大于 ’+‘ ’-‘
      • 运算遵循左结合性,即先出现的运算符优先级更高
      • 对于左括号’(‘,优先级最高
      • 当右括号入栈时,operator一直出栈,直到遇到左括号

      即遵循如果operator栈顶元素运算符的优先级大于等于当前运算符的优先级,栈顶元素要出栈,进行运算,之后将当前运算符入栈,栈中肯定保持当前运算符的优先级大于下面所有运算符

    2. 对于operand,栈里面只存储数字,会有从这个栈里取出栈顶两个元素进行计算,将计算结果压栈

  3. 主方法中,按以下步骤:

    1. input接受用户输入字符串(要求使用英文)

    2. 调用expression方法,传入输入字符数组

      在expression方法中,先用判断括号是否匹配方法,若不匹配,提示错误信息,结束程序。否则依次遍历得到每个字符,并记录遍历到的:

      ​ 如果是空格跳过

      1. 如果字符是数字,使用while继续遍历,直到当前字符不是数字,将遍历得到的字符拼接之后转为double类型压入栈中
      2. 如果是运算符,将栈顶元素于当前元素的优先级进行比较,如果栈顶元素优先级大于等于当前运算符,则栈顶元素出栈,进行运算,当前字符进栈
      3. 如果是左括号,压栈
      4. 如果是右括号,只要没有到左括号,那么operator一直出栈,进行运算
      5. 如果都不是,表明遇到其他不合法字符,提示表达式输入错误,结束程序

      遍历完表达式之后,operator栈里还有一个元素,operand栈里还有两个元素,将最后计算结果压栈,最后返回最终结果。

    3. 用到的辅助方法:

      1. 判断是否是运算符bool isop(char c);

      2. 求运算符优先级int precede(char c);

      3. 计算两数运算结果double twoResult(char op,double a,double b);

      4. 检查括号是否匹配bool IsParenthesesMatch(char[] str);

        实现步骤:

        1. 创建存放字符的栈stack
        2. 遇到左括号,入栈
        3. 遇到右括号,如果栈为空或者栈顶元素不是是左括号,返回false;如果是左括号,出栈
        4. 到最后如果栈非空返回false

        考虑以下不匹配情况:

        1. 括号数不匹配
        2. 顺序不匹配

上面考虑到的表达式错误很少,仅包含括号不匹配,表达式中有除加减乘除、左右括号和空格意外的其他字符,对于运算符相邻没有考虑到,比如"3+2**6-9+(12-3)*2".

运算也只限于输入是整数,进行加减乘除运算。

主要可以学习到的是熟练使用栈,以及了解栈在解题中的作用。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 表达式计算
{
    internal class MyStack<T>
    {
        private T[] values;
        private int top;

        public MyStack() 
        {
            values = new T[10];
            top = 0;
        }

        public bool IsEmpty()
        {
            return top == 0;
        }

        public bool IsFull()
        {
            return top == values.Length;
        }

        public void Push(T value)
        {
            if (IsFull())
            {
                T[] newArray = new T[values.Length * 2];
                Array.Copy(values, newArray, values.Length);
                values = newArray;
            }
            values[top++] = value;
        }

        public T Pop()
        {
            if(IsEmpty())
            {
                throw new InvalidOperationException("Stack is empty.");
            }

            return values[--top];
        }

        public T Peek()
        {
            if (IsEmpty())
            {
                throw new InvalidOperationException("Stack is empty.");
            }
            return values[top - 1];
        }

        public int Count()
        {
            return top;
        }

    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace 表达式计算
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("请输入表达式:");
            //"3+(5-(8/2)*7)*2+100"
            //"3+8-7"
            //"3+2**6-9+(12-3)*2"
            //"3**2"
            string input = "(5 + 3) * (7 - 2) + 18 / (4 + 2) - 9";
            double result = expression(input.ToCharArray());
            Console.WriteLine(result);
        }

        public static double expression(char[] str)
        {
            if (!IsParenthesesMatch(str))
            {
                Console.WriteLine("表达式括号不匹配");
                Environment.Exit(1);
            }
            //创建运算符栈
            MyStack<char> Operator = new MyStack<char>();
            //创建操作数栈
            MyStack<double> Operand = new MyStack<double>();

            for(int i = 0; i < str.Length; i++)
            {
                if (str[i] ==' ')
                {
                    continue;
                }
                else if (isDigit(str[i]))
                {
                    string s = str[i].ToString();
                    i++;
                    while ((i <= str.Length - 1) && isDigit(str[i]))
                    {
                        s+= str[i].ToString();
                        i++;
                    }
                    //执行到这里,str[i]不是数字字符,i要回退1,因为下次i会自增
                    i--;
                    Operand.Push(double.Parse(s));
                }
                else if (isop(str[i]))
                {
                    //如果当前栈为空
                    if (Operator.IsEmpty())
                    {
                        Operator.Push(str[i]);
                        continue;
                    }
;                    //如果栈顶元素优先级大于等于当前运算符的优先级
                    if (precede(Operator.Peek()) >= precede(str[i]))
                    {
                        //运算符栈顶元素出栈,操作数出栈
                        if (Operand.Count() >= 2)
                        {
                            Operand.Push(twoResult(Operator.Pop(), Operand.Pop(), Operand.Pop()));
                        }
                        else
                        {
                            //表明可能有两个优先级相等的运算符相邻
                            Console.WriteLine("表达式有错误。");
                            Environment.Exit(1);
                        }
                    }
                    //由于不管栈顶元素优先级是否大于等于当前运算符的优先级,当前运算符都要入栈
                    Operator.Push(str[i]);

                }
                else if (str[i] == '(')
                {
                    Operator.Push(str[i]);
                }
                else if (str[i] == ')')
                {
                    char opstr;
                    while((opstr = Operator.Pop()) != '(')
                    {
                        Operand.Push(twoResult(opstr, Operand.Pop(), Operand.Pop()));
                    }
                }
                //其他字符
                else
                {
                    Console.WriteLine("表达式有错误。");
                    Environment.Exit(1);
                }
            }

            //对剩余在栈里的元素进行操作
            while (!Operator.IsEmpty())
            {
                Operand.Push(twoResult(Operator.Pop(), Operand.Pop(), Operand.Pop()));
            }

            

            //返回最终结果
            return Operand.Peek();
        }


        public static bool isDigit(char c)
        {
            if(c >= '0' && c <= '9')
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public static bool isop(char c)
        {
            if (c == '+' || c == '-' || c == '*' || c == '/')
            {
                return true;
            }
            return false;
        }

        
        public static int precede(char c)
        {
            switch (c)
            {
                case '+':
                case '-':
                    return 1;
                case '*':
                case '/':
                    return 2;
                default:
                    return 0;
            }
        }


        public static double twoResult(char op,double a,double b)
        {
            switch (op)
            {
                case '+':
                    return b + a;
                case '-':
                    return b - a;
                case '*':
                    return b * a;
                case '/':
                    if(a == 0)
                    {
                        throw new DivideByZeroException("除数不能为零");
                    }
                    return b / a;
                default:
                    throw new ArgumentException("无效的运算符");
            }
        }

        public static bool IsParenthesesMatch(char[] str)
        {
            //保存括号
            MyStack<char> temp= new MyStack<char>();

            foreach (char c in str)
            {
                //c为括号
                if(c == '(')
                {
                    temp.Push(c);
                }
                else if(c == ')')
                {
                    if(temp.IsEmpty()||temp.Peek() != '(')
                    {
                        return false;
                    }
                    //将左括号出栈
                    temp.Pop();
                }
            }

            return temp.IsEmpty();

        }
    }
}


http://www.kler.cn/a/396004.html

相关文章:

  • R语言贝叶斯分析:INLA 、MCMC混合模型、生存分析肿瘤临床试验、间歇泉喷发时间数据应用|附数据代码...
  • 力扣 最长公共前缀-14
  • 聊天服务器(9)一对一聊天功能
  • 力扣 LeetCode 239. 滑动窗口最大值(Day5:栈与队列)
  • 【Window主机访问Ubuntu从机——Xrdp配置与使用】
  • 二分查找--快速地将搜索空间减半
  • pytorch中的transform用法
  • 21.<基于Spring图书管理系统②(图书列表+删除图书+更改图书)(非强制登录版本完结)>
  • Kafka入门:Java客户端库的使用
  • C语言.冒泡排序的练习
  • 在word文档中,内容是一段英文,一段英文的显示,且段落的前后都有空行,我如何只去掉英文段落后面的空行。
  • 25浙江省考-28天学行测-Day5 Day6-判断推理(中)
  • reduce-scatter:适合分布式计算;Reduce、LayerNorm和Broadcast算子的执行顺序对计算结果的影响,以及它们对资源消耗的影响
  • R门 - rust第一课陈天 -内存知识学习笔记
  • Apache Doris:监控与运维及系统调优
  • 【RabbitMQ】07-业务幂等处理
  • Tomcat NIO 配置实操指南
  • JVM——类加载器、类加载器的分类
  • 【Ubuntu侧边菜单点击没反应】【Ubuntu 20.04】【浏览器、文件夹点击没反应】
  • LabVIEW开发相机与显微镜自动对焦功能
  • 消息中间件分类
  • 《Django 5 By Example》阅读笔记:p17-p53
  • 去中心化存储:Web3数据安全新标准
  • Wireshark中的length栏位
  • YOLO理解
  • 一个C++线程安全的栈数据结构的例子