C#学习之逆波兰公式简单实现
来源:互联网 发布:2017淘宝可以买彩票吗 编辑:程序博客网 时间:2024/06/07 05:49
Stack<T>和Stack
Stack<T>和Stack则是后进先出的数据结构,通过Push和Pop法实现添加元素到队列的顶部和从队列的顶部移除元素。同样也提供了Peek方法、Count属性和ToArray方法。
栈的实践使用:逆波兰公式
表达式一般由操作数(Operand)、运算符(Operator)组成,例如算术表达式中,通常把运算符放在两个操作数的中间,
这称为中缀表达式(Infix Expression),如A+B。
波兰数学家Jan Lukasiewicz提出了另一种数学表示法,它有两种表示形式:
把运算符写在操作数之前,称为波兰表达式(Polish Expression)或前缀表达式(Prefix Expression),如+AB;
把运算符写在操作数之后,称为逆波兰表达式(Reverse Polish Expression)或后缀表达式(Suffix Expression),如AB+;
其中,逆波兰表达式在编译技术中有着普遍的应用。
算法:
一、 将中缀表达式转换成后缀表达式算法:
1、从左至右扫描一中缀表达式。
2、若读取的是操作数,则判断该操作数的类型,并将该操作数存入操作数堆栈
3、若读取的是运算符
(1) 该运算符为左括号"(",则直接存入运算符堆栈。
(2) 该运算符为右括号")",则输出运算符堆栈中的运算符到操作数堆栈,直到遇到左括号为止。
(3) 该运算符为非括号运算符:
(a) 若运算符堆栈栈顶的运算符为括号,则直接存入运算符堆栈。
(b) 若比运算符堆栈栈顶的运算符优先级高或相等,则直接存入运算符堆栈。
(c) 若比运算符堆栈栈顶的运算符优先级低,则输出栈顶运算符到操作数堆栈,并将当前运算符压入运算符堆栈。
4、当表达式读取完成后运算符堆栈中尚有运算符时,则依序取出运算符到操作数堆栈,直到运算符堆栈为空。
二、逆波兰表达式求值算法:
对后缀表达式求值比直接对中缀表达式求值简单。在后缀表达式中,不需要括号,而且操作符的优先级也不再起作用了。您可以用如下算法对后缀表达式求值:
- 初始化一个空堆栈
- 从左到右读入后缀表达式
- 如果字符是一个操作数,把它压入堆栈。
- 如果字符是个操作符,弹出两个操作数,执行恰当操作,然后把结果压入堆栈。如果您不能够弹出两个操作数,后缀表达式的语法就不正确。
- 到后缀表达式末尾,从堆栈中弹出结果。若后缀表达式格式正确,那么堆栈应该为空。
using System;using System.Collections.Generic;using System.Diagnostics;//System.Diagnostics命名空间 包含了能够与系统进程 事件日志 和性能计数器进行交互的类 //一般用于帮助诊断和调试应用程序 //查考链接 https://www.douban.com/note/220654090/namespace ConsoleAppTest{ class Program { //是否为数字 //判断是否为整数字符串 static bool isNumber(string message) { //判断是否为整数字符串 //是的话则将其转换为数字并将其设为out类型的输出值、返回true, 否则为false int result = -1; //result 定义为out 用来输出值 try { //当数字字符串的为是少于4时,以下三种都可以转换,任选一种 //如果位数超过4的话,请选用Convert.ToInt32() 和int.Parse() //result = int.Parse(message); //result = Convert.ToInt16(message); result = Convert.ToInt32(message); return true; } catch { return false; } } //是否为操作符 static bool isOpertor(string c) { return c == "+" || c == "-" || c == "*" || c == "/" || c == "(" || c == ")"; } //判断操作符优先级大小 static bool comparePriority(string op1, string op2) { return getPriorityValue(op1) > getPriorityValue(op2); } //获取操作符优先级 static int getPriorityValue(string c) { int priority; switch (c) { case "+": priority = 1; break; case "-": priority = 1; break; case "*": priority = 2; break; case "/": priority = 2; break; default: priority = 0; break; } return priority; } //计算值 static int getOperand(string op, int num1, int num2) { int result = -1; switch (op) { case "+": result = num1 + num2; break; case "-": result = num1 - num2; break; case "*": result = num1 * num2; break; case "/": result = num1 / num2; break; } return result; } static Stack<string> changeExpression(List<string> beforeExps) { Stack<string> operand = new Stack<string>();//操作数 Stack<string> opertor = new Stack<string>();//操作符 //遍历中序表示 int length = beforeExps.Count; //判断是否为操作数 for (int i = 0; i < length; i++) { string c = beforeExps[i]; if (isNumber(c)) { //操作数 存在操作数栈 operand.Push(c); } else { //为运算符 //若运算符为"("直接存入到运算符栈中 if (c == "(") { opertor.Push(c); } else if (c == ")") { //该运算符为右括号")",则输出运算符堆栈中的运算符到操作数堆栈,直到遇到左括号为止。 将"("出栈 while (opertor.Peek() != "(") { string stringvalue = opertor.Pop(); operand.Push(stringvalue); } opertor.Pop(); } else { // 该运算符为非括号运算符: //考虑栈顶为空的情况 if (opertor.Count <= 0) { opertor.Push(c); continue; } // (a) 若运算符堆栈栈顶的运算符为括号,则直接存入运算符堆栈。 ////符合为左括号 直接存入运算符 if (opertor.Peek() == "(") { opertor.Push(c); } else { //(b) 若比运算符堆栈栈顶的运算符优先级高或相等,则直接存入运算符堆栈。 if (comparePriority(c, opertor.Peek())) { opertor.Push(c); } else { // (c) 若比运算符堆栈栈顶的运算符优先级低,则输出栈顶运算符到操作数堆栈,并将当前运算符压入运算符堆栈。 string stringvalue = opertor.Pop(); operand.Push(stringvalue); opertor.Push(c); } } } } } //4、当表达式读取完成后运算符堆栈中尚有运算符时,则依序取出运算符到操作数堆栈,直到运算符堆栈为空。 while (opertor.Count > 0) { string stringvalue = opertor.Pop(); operand.Push(stringvalue); } //反转operand 获取正常的会缀表达式 Stack<string> resultSt = new Stack<string>(); while (operand.Count > 0) { string stringvalue = operand.Pop(); resultSt.Push(stringvalue); } return resultSt; } //转换string为list表 static List<string> changeStrToList(string str) { List<string> resultSt = new List<string>(); List<int> sortNum = new List<int>(); bool isConNum = false; foreach(char c in str) { if (isOpertor(c.ToString())) { if (isConNum && sortNum.Count > 0) { //添加数字 int num = 0; for (int i = sortNum.Count -1 ; i >= 0; i--) { if (i == sortNum.Count - 1) { num = num + sortNum[i]; }else{ num = num + sortNum[i] * 10 * (sortNum.Count - 1 - i ); } } resultSt.Add(num.ToString()); sortNum.Clear(); } isConNum = false; //如果是操作符直接添加 resultSt.Add(c.ToString()); }else{ //如果是数字 isConNum = true; sortNum.Add(int.Parse(c.ToString())); } } if (sortNum.Count > 0) { //添加数字 int num = 0; for (int i = sortNum.Count - 1; i >= 0; i--) { if (i == sortNum.Count - 1) { num = num + sortNum[i]; } else { num = num + sortNum[i] * 10 * (sortNum.Count - 1 - i); } } resultSt.Add(num.ToString()); sortNum.Clear(); } return resultSt; } //计算逆波兰公式 static int calculateExpression(Stack<string> st) { //临时存储计算数据 Stack<string> reslutSt = new Stack<string>(); while(st.Count > 0) { string numStr = st.Peek(); if (isNumber(numStr)) { //如果字符是一个操作数,把它压入堆栈。 reslutSt.Push(numStr); } else { //如果字符是个操作符,弹出两个操作数,执行恰当操作, //然后把结果压入堆栈。如果您不能够弹出两个操作数,后缀表达式的语法就不正确。 int number1 = int.Parse(reslutSt.Pop()); int number2 = int.Parse(reslutSt.Pop()); int value = getOperand(numStr, number2, number1); reslutSt.Push(value.ToString()); } st.Pop(); } return int.Parse(reslutSt.Peek()); } static void Main(string[] args) { Console.WriteLine("C# 逆波兰公式 输入您要计算的公式,按enter结束"); //string inputStr = Console.ReadLine(); string teststr = Console.ReadLine(); List<string> inputStr = changeStrToList(teststr); Console.WriteLine("公式为:"); foreach (string str in inputStr) { Console.Write("{0} ", str); } Console.Write(" ===> "); Stack<string> changeSt = changeExpression(inputStr); foreach (string str in changeSt) { Console.Write("{0} ", str); } Console.WriteLine("逆波兰公式计算:"); //计算公式的值 int resultValue = calculateExpression(changeSt); Console.WriteLine("{0} = {1} ", teststr ,resultValue); Console.ReadKey(); } }}
0 0
- C#学习之逆波兰公式简单实现
- C#学习之逆波兰公式简单实现
- 字符串公式解析器——使用“逆波兰式算法”及C#实现
- 字符串公式解析器——使用“逆波兰式算法”及C#实现
- 字符串公式解析器——使用“逆波兰式算法”及C#实现
- 字符串公式解析器——使用“逆波兰式算法”及C#实现
- C++学习之(栈) 实践之(逆波兰公式)
- 二叉树解析实现逆波兰公式算法
- 二叉树解析实现逆波兰公式算法
- 二叉树解析实现逆波兰公式算法
- EXCEL之:公式的逆波兰序表达式
- 算法学习一之逆波兰表达式
- 算法学习之递归--逆波兰表达式
- 简单逆波兰计算器
- c# 数学表达式分析(采用逆波兰方式实现)
- C语言实现的简单的逆波兰计算器
- 关于Java写逆波兰表达式堆栈操作简单实现
- C++逆波兰表达式转化实现简单计算器
- 大神是如何装逼的 之 vim插件使用taglist和nerdtree
- google官方架构MVP解析与实战-(从零开始搭建android框架系列(3))
- (OK) Creates Docker-based Virtual PC containers for use inside GNS3 as end hosts.
- 找人代写安卓端DICOM查看器
- Memcached实现机制
- C#学习之逆波兰公式简单实现
- ptr_vector
- 实用技巧——获取验证码的倒计时
- 深度学习领域相关资料
- 假设有n个布尔变量x1, ..., xn,输出其所有可能的真值集合
- Android 更新UI的两种方法——handler和runOnUiThread()
- Swagger实践和总结
- 基于DFS的拓扑排序
- 不容错过,最全的安卓架构合集-(从零开始搭建android框架系列(2))