C#数据结构与算法系列(九):栈实现综合计算器(中缀表达式)
1.问题介绍

2.实现思路

3.代码实现
第一个版本(采用这个)
public class ArrayStack
{
private int _maxSize;
private int[] _arr;
private int _top = -; /// <summary>
/// 初始化栈
/// </summary>
/// <param name="maxSize"></param>
public ArrayStack(int maxSize)
{
_maxSize = maxSize;
_arr = new int[_maxSize];
} /// <summary>
/// 栈是否为空
/// </summary>
/// <returns></returns>
public bool IsEmpty() => _top == -; /// <summary>
/// 栈是否满
/// </summary>
/// <returns></returns>
public bool IsFull() => _top == _maxSize-; /// <summary>
/// 入栈
/// </summary>
/// <param name="value"></param>
public void Push(int value)
{
if (IsFull())
{
Console.WriteLine("栈满");
}
else
{
_top++;
_arr[_top] = value;
}
}
/// <summary>
/// 出栈
/// </summary>
/// <returns></returns>
public int Pop()
{
if (IsEmpty())
{
throw new Exception("栈空");
}
int value = _arr[_top]; _top--; return value;
} /// <summary>
/// 栈列表
/// </summary>
public void List()
{
if (IsEmpty())
{
Console.WriteLine("栈空");
}
else
{
for (int i = _top; i >= ; i--)
{
Console.WriteLine($"stack:[{i}]={_arr[i]}");
}
}
} /// <summary>
/// 返回当前栈顶的值
/// </summary>
/// <returns></returns>
public int Peek() => _arr[_top]; /// <summary>
/// 优先级判断
/// </summary>
/// <param name="oper"></param>
/// <returns></returns>
public int Priority(int oper)
{
if (oper == '*' || oper == '/')
{
return ;
}
else if (oper == '+' || oper == '-')
{
return ;
}
else return -;
}
/// <summary>
/// 计算
/// </summary>
/// <param name="num1"></param>
/// <param name="num2"></param>
/// <param name="oper"></param>
/// <returns></returns>
public int Cal(int num1, int num2, int oper)
{
int result = ;
switch (oper)
{
case '+':
result = num1 + num2;
break;
case '-':
result = num2 - num1; //注意顺序
break;
case '*':
result = num1 * num2;
break;
case '/':
result = num2 / num1; //注意顺序
break;
default:
break;
}
return result;
} /// <summary>
/// 判断是否是操作符
/// </summary>
/// <param name="val"></param>
/// <returns></returns>
public bool IsOper(char val)
{
return val == '-' || val == '+' || val == '*' || val == '/';
}
}
using System; namespace DataStructure
{
public class Calculator
{
public static void Test()
{
string expression = "300+2*3+2-1"; ArrayStack numStack = new ArrayStack(); ArrayStack operStack = new ArrayStack(); //把字符串转换成char数组
char[] arr = expression.ToCharArray(); /*
public unsafe char[] ToCharArray() int length = this.Length;
char[] array = new char[length];
if (length > 0)
{
fixed (char* ptr = &this.m_firstChar)
{
fixed (char* ptr2 = array)
{
string.wstrcpy(ptr2, ptr, length);
}
}
}
return array; */
//结果
int result = ; int num1 = ; int num2 = ; int oper = ; string keepNum = ""; for (int i = ; i < arr.Length; i++)
{
//判断是不是操作符
if (operStack.IsOper(arr[i]))
{
//如果不是空的
if (!operStack.IsEmpty())
{
//如果符号栈中有操作符,就进行比较,如果当前操作符的优先级小于或等于栈中的操作符,就需要从栈中pop出两个数
//再从符号栈中pop出一个符号,进行运算,将得到结果,入数栈,然后再把当前操作符入符号栈
if (operStack.Priority(arr[i]) <= operStack.Priority(operStack.Peek()))
{
num1 = numStack.Pop(); num2 = numStack.Pop(); oper = operStack.Pop(); //计算
result = numStack.Cal(num1, num2, oper); numStack.Push(result); operStack.Push(arr[i]);
}
else
{
//如果当前操作符的优先级大于栈中的操作符就直接入符号栈
operStack.Push(arr[i]);
}
}
else
{
//为空就直接入符号栈
operStack.Push(arr[i]);
}
}
else
{
//把字符转成字符串
keepNum += arr[i]; for (int j = i + ; j < arr.Length; j++)
{
//判断arr[i]的面是否是操作符 如果不是则拼接
if (!numStack.IsOper(arr[j]))
{
keepNum += arr[j]; i++;//当确定后一个是数字的时候 索引也要跟着往后移
}
//如果是则终止
else break;
} numStack.Push(int.Parse(keepNum)); //一定要置空,否则会保留上一次操作
keepNum = "";
}
}
//当数字占和符号栈都不为空的情况下才进循环
while (!operStack.IsEmpty() && !numStack.IsEmpty())
{
//当符号栈为空的时候就跳出循环
if (operStack.IsEmpty()) break; num1 = numStack.Pop(); num2 = numStack.Pop(); oper = operStack.Pop(); result = numStack.Cal(num1, num2, oper); numStack.Push(result);
} Console.WriteLine($"表达式{expression}={numStack.Pop()}");
}
}
}
第二个版本
public class ArrayStack {
private int maxSize;
private int[] stack;
private int top = -1;
public ArrayStack(int maxSize) {
this.maxSize = maxSize;
stack = new int[maxSize];
}
public boolean isEmpty() {
return top == -1;
}
public boolean isFull() {
return top == maxSize;
}
public void push(int value) {
if (isFull()) {
System.out.println("栈已满!");
} else {
top++;
stack[top] = value;
}
}
public int pop() {
if (isEmpty()) {
throw new RuntimeException("栈为空");
}
int result = stack[top];
top--;
return result;
}
public void list() {
if (isEmpty()) {
System.out.println("栈为空");
} else {
for (int i = top; i >= 0; i--) {
System.out.printf("stack[%d]=%d\n", i, stack[i]);
}
}
}
public int peek() {
return stack[top];
}
public boolean isOperate(int vaule) {
return vaule == '*' || vaule == '/' || vaule == '+' || vaule == '-';
}
public int calculate(int num1, int num2, int operate) {
switch (operate) {
case '*':
return num1 * num2;
case '/':
return num2 / num1;
case '+':
return num1 + num2;
case '-':
return num2 - num1;
default:
return 0;
}
}
public int priority(int operate) {
if (operate == '*' || operate == '/') {
return 1;
} else if (operate == '+' || operate == '-') {
return 0;
} else return -1;
}
}
public class Calculator {
public static void main(String[] args) {
String expression = "3+2*5-1";
ArrayStack numStack = new ArrayStack(10);
ArrayStack operateStack = new ArrayStack(10);
int num1, num2, operate, result;
int index = num1 = num2 = operate = result = 0;
char value;
while (true) {
value = expression.substring(index, index + 1).charAt(0);
if (operateStack.isOperate(value)) {
if (operateStack.isEmpty()) {
operateStack.push(value);
} else {
if (operateStack.priority(value) <= operateStack.priority(operateStack.peek())) {
num1 = numStack.pop();
num2 = numStack.pop();
operate = operateStack.pop();
result = operateStack.calculate(num1, num2, operate);
numStack.push(result);
operateStack.push(value);
} else {
operateStack.push(value);
}
}
} else {
String keepNum = "" + value;
if (index == expression.length() - 1) {
numStack.push(Integer.parseInt(keepNum));
break;
} else {
char nextNum = expression.substring(index + 1, index + 2).charAt(0);
if (operateStack.isOperate(nextNum)) {
numStack.push(Integer.parseInt(keepNum));
} else {
keepNum += nextNum;
numStack.push(Integer.valueOf(keepNum));
keepNum = "";
}
}
}
index++;
}
while (true) {
if (operateStack.isEmpty()) {
break;
}
num1 = numStack.pop();
num2 = numStack.pop();
operate = operateStack.pop();
result = operateStack.calculate(num1, num2, operate);
numStack.push(result);
}
System.out.printf("\n%s的结果是%d", expression, numStack.pop());
}
}
C#数据结构与算法系列(九):栈实现综合计算器(中缀表达式)的更多相关文章
- javascript实现数据结构与算法系列:栈 -- 顺序存储表示和链式表示及示例
栈(Stack)是限定仅在表尾进行插入或删除操作的线性表.表尾为栈顶(top),表头为栈底(bottom),不含元素的空表为空栈. 栈又称为后进先出(last in first out)的线性表. 堆 ...
- 数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解
数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解 对数组有不了解的可以先看看我的另一篇文章,那篇文章对数组有很多详细的解析,而本篇文章则着重讲动态数组,另一篇文章链接 ...
- 数据结构与算法系列2 线性表 链表的分类+使用java实现链表+链表源码详解
数据结构与算法系列2.2 线性表 什么是链表? 链表是一种物理存储单元上非连续,非顺序的存储结构,数据元素的逻辑顺序是通过链表的链接次序实现的一系列节点组成,节点可以在运行时动态生成,每个节点包括两个 ...
- C语言- 基础数据结构和算法 - 09 栈的应用_中缀表达式转后缀表达式20220611
09 栈的应用_中缀表达式转后缀表达式20220611 听黑马程序员教程<基础数据结构和算法 (C版本)>, 照着老师所讲抄的, 视频地址https://www.bilibili.com/ ...
- C#数据结构与算法系列(八):栈(Stack)
1.介绍 栈是一个先入后出(FILO-First In Last Out)的有序列表 栈是限制线性表中元素的插入和删除只能在线性表的同一端进行的特殊线性表.允许插入和删除的一端,为变化的一端,称为栈顶 ...
- JavaScript 数据结构与算法之美 - 栈内存与堆内存 、浅拷贝与深拷贝
前言 想写好前端,先练好内功. 栈内存与堆内存 .浅拷贝与深拷贝,可以说是前端程序员的内功,要知其然,知其所以然. 笔者写的 JavaScript 数据结构与算法之美 系列用的语言是 JavaScri ...
- 数据结构与算法JavaScript (一) 栈
序 数据结构与算法JavaScript这本书算是讲解得比较浅显的,优点就是用javascript语言把常用的数据结构给描述了下,书中很多例子来源于常见的一些面试题目,算是与时俱进,业余看了下就顺便记录 ...
- 数据结构与算法系列研究五——树、二叉树、三叉树、平衡排序二叉树AVL
树.二叉树.三叉树.平衡排序二叉树AVL 一.树的定义 树是计算机算法最重要的非线性结构.树中每个数据元素至多有一个直接前驱,但可以有多个直接后继.树是一种以分支关系定义的层次结构. a.树是n ...
- PHP 程序员学数据结构与算法之《栈》
“要成高手,必练此功”. 要成为优秀的程序员,数据结构和算法是必修的内容.而现在的Web程序员使用传统算法和数据结构都比较少,因为很多算法都是包装好的,不用我们去操心具体的实现细节,如PHP的取栈 ...
- 数据结构与算法系列——排序(4)_Shell希尔排序
1. 工作原理(定义) 希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本.但希尔排序是非稳定排序算法. 希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入 ...
随机推荐
- Android_适配器(adapter)之SimpleAdapter
概述 SimpleAdapter是一种 简单的适配器,将静态数据映射到布局xml对应的视图上.它也是BaseAdapter的子类. SimpleAdapter数据映射的组件有3类(从官网api或Sim ...
- html5学习之路_001
安装环境 安装intellij idea作为开发环境 打开环境 新建一个html文件,打开之后出现代码框架,再次基础上继续编码即可,例如: <!DOCTYPE html> <html ...
- 485通信——驱动 MX64/MX28 舵机
背景:在使用STM32调试MX64舵机时,由于控制该舵机需要采用RS485通信协议,因此需要从单片机的串口经过一个TTL转485通信的模块再与舵机进行通信. 485通信特点: 485通信采用差分信号: ...
- 运用惰性删除和定时删除实现可过期的localStorage缓存
localStorage简介 使用localStorage可以在浏览器中存储键值对的数据.经常被和localStorage一并提及的是sessionStorage,它们都可以在当浏览器中存储键值对的数 ...
- uni-app之uni.showToast()image路径问题
uni-app的API中,showToast的icon值只有success,loading,none三种显示,失败没有图标.如果失败时需要显示图标,就要用到自定义图标 image 了. uni.sho ...
- JAVA实现对称加密
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 一.对称加密算法DES 1.概述:采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这 ...
- Java实现 LeetCode 819 最常见的单词(暴力)
819. 最常见的单词 给定一个段落 (paragraph) 和一个禁用单词列表 (banned).返回出现次数最多,同时不在禁用列表中的单词. 题目保证至少有一个词不在禁用列表中,而且答案唯一. 禁 ...
- Java实现 LeetCode 795 区间子数组个数 (暴力分析)
795. 区间子数组个数 给定一个元素都是正整数的数组A ,正整数 L 以及 R (L <= R). 求连续.非空且其中最大元素满足大于等于L 小于等于R的子数组个数. 例如 : 输入: A = ...
- Java实现 LeetCode 206 反转链表
206. 反转链表 反转一个单链表. 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL ...
- 从linux源码看socket的阻塞和非阻塞
从linux源码看socket的阻塞和非阻塞 笔者一直觉得如果能知道从应用到框架再到操作系统的每一处代码,是一件Exciting的事情. 大部分高性能网络框架采用的是非阻塞模式.笔者这次就从linux ...