采用顺序栈,实现一个简易计算器

2023-05-16

 首先需要区分中缀表达式与后缀表达式(中缀转为后缀即可进行计算):

例如中缀表达式为12+3-(6+2)*2-15/3 

那么所求的后缀表达式的步骤为

1. 判断12是数字,不入栈,输出12。即为 12

2. 判断+是运算符,入栈。即为 12

3. 判断3是数字,不入栈,输出3。即为 12 3

4. 判断-是运算符,入栈,此时需要判断符号之间的优先级,低于栈顶符号才可以输出。输出+。即为 12 3 +

5. 判断(是特殊符号,需要特殊定义,入栈,但不输出。即为 12 3 +

6.判断 6是数字,不入栈,输出。即为 12 3 +6

7.判断+是运算符,入栈,不输出。即为 12 3 +6 

8.判断2是数字,不入栈,输出。即为 12 3 +6  2

9.判断)是特殊符号,入栈,前面有(,即将之前存入的内容全部输出。即为 12 3 +6 2 +

10. 判断*是运算符,入栈,不输出。即为12 3 +6 2 +

11. 判断2是数字,不入栈,输出。即为 12 3 +6  2 +2 

12. 判断-是运算符,而*的优先级高于-,所以在-之前的内容全部输出。即为 12 3 +6 2 +2  *-

13.判断15是数字,不入栈,输出。即为 12 3 +6 2 +2 *- 15

14.判断/是运算符,入栈,不输出。即为 12 3 +6 2 +2 *- 15

15.判断3是数字,不入栈,输出。即为 12 3 +6 2 +2 *- 15 3

15,剩下的所有元素都输出。最终的表达式为 12 3 +6 2 +2 *- 15 3 /-

 主要代码:

1.中缀表达式转为后缀表达式

//中缀表达式转为后缀表达式
void TranslateExpress(char str[], char exp[]) {
	stack s;
	char ch, e{};
	int i = 0, j = 0;
	InitStack(&s);
	ch = str[i++];
	while (ch != '\0') {

		switch (ch) {

		case '(':
			Push(&s, ch);//在栈s已经存在的情况下,插入元素ch为新的栈顶元素
			break;
		case ')':
			while (GetTop(s, &e) && e != '(') {//遍历,在栈s已经存在而且非空,返回栈顶的元素e,而且不修改栈顶指针,同时禁止再出现‘(’

				Pop(&s, &e);//在栈s已经存在而且非空的情况下,删除s的栈顶元素,并用e返回其值
				exp[j++] = e;//继续遍历
			}
			Pop(&s, &e);
			break;
		case '+':
		case '-':
			while (!StackEmpty(s) && GetTop(s, &e) && e != '(') {//注意s应当不是空栈

				Pop(&s, &e);
				exp[j++] = e;
			}
			Push(&s, ch);
			break;
		case '*':
		case '/':
			while (!StackEmpty(s) && GetTop(s, &e) && e == '/' || e == '*' || e == '^') {
				Pop(&s, &e);
				exp[j++] = e;
			}
			Push(&s, ch);
			break;
		case '^':
			while (!StackEmpty(s) && GetTop(s, &e) && e == '^') {

				Pop(&s, &e);
				exp[j++] = e;
			}
			Push(&s, ch);
			break;
		case ' '://中间不允许输入空格
			break;
		default://出现错误的处理办法
			while (ch >= '0' && ch <= '9') {
				exp[j++] = ch;
				ch = str[i++];
			}
			i--;
			exp[j++] = ' ';
		}
		ch = str[i++];
	}
	while (!StackEmpty(s)) {//将剩余的内容全部出栈,此时完成所有的后缀表达式

		Pop(&s, &e);
		exp[j++] = e;
	}
	exp[j] = NULL;//确保已经清空栈

2.计算后缀表达式

 

//计算表达式的值,类型为double是为了防止出现小数导致错误
double ComputeExpress(char a[]) {

	opstack s;
	int i = 0, value;
	float x1, x2, result;
	s.top = -1;//一般情况下,栈空时栈顶为-1
	while (a[i] != NULL) {

		if (a[i] != ' ' && a[i] >= '0' && a[i] <= '9') {
			value = 0;
			while (a[i] != ' ') {//判断该数为几位数

				value = 10 * value + a[i] - '0';//将字符转化为整数进行计算
				i++;
			}
			s.top++;
			s.data[s.top] = value;//判断所求数字的具体之后,再入栈,即压入所得数据
		}
		else {
			switch (a[i]) {//进行+,-,*,/ 以及^的运算


			case '+':
				x1 = s.data[s.top--];
				x2 = s.data[s.top--];
				result = x1 + x2;        //计算x1+x2
				s.data[++s.top] = result;//同上,压入所得的数据
				break;
			case '-':
				x1 = s.data[s.top--];
				x2 = s.data[s.top--];
				result = x2 - x1;
				s.data[++s.top] = result;
				break;
			case '*':
				x1 = s.data[s.top--];
				x2 = s.data[s.top--];
				result = x1 * x2;
				s.data[++s.top] = result;
				break;
			case '/':
				x1 = s.data[s.top--];
				x2 = s.data[s.top--];
				result = x2 / x1;
				s.data[++s.top] = result;
				break;
			case '^':
				x1 = s.data[s.top--];
				x2 = s.data[s.top--];
				result = pow(x2, x1); //pow(a,b)函数表示以a为底数的b次方<数学函数,需要导入math.h头文件>
				s.data[++s.top] = result;
				break;
			}
			i++;//继续遍历
		}
	}
	if (!s.top != -1) {
		result = s.data[s.top];
		s.top--;
		if (s.top == -1)
			return result;
		else {  //exit(-1);
			printf("----------表达式错误,请重新输入!-----------");
			
		}
	}
}

 总体代码:

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define MAXSIZE 50       //顺序栈存储空间的初始分配量

typedef struct {//数字栈结构体
	double data[MAXSIZE];
	int top;
} opstack;

typedef struct {//符号栈结构体
	char data[MAXSIZE];
	int top;
} stack;


void InitStack(stack* s) {//构造一个空栈并初始化栈<s为结构体指针>
	s->top = 0;
}


int GetTop(stack s, char* e) {//栈顶要单独取出,返回s的栈顶元素,不修改栈顶指针
	if (s.top <= 0)
		return 0;
	else {
		*e = s.data[s.top - 1];
		return 1;
	}
}


bool Pop(stack* s, char* e) {//出栈操作

	if (s->top <= 0)//栈空
		return false;
	else
		*e = s->data[--s->top];
	return true;
}


bool Push(stack* s, char e) {//入栈操作

	if (s->top >= MAXSIZE)
		return false;
	else
		s->data[s->top++] = e;
	return true;
}

int StackEmpty(stack s) {//判断栈空

	if (s.top == 0)
		return true;
	else return false;
}


double ComputeExpress(char a[]) {//计算表达式值,类型为double是为了防止出现小数导致错误


	opstack s;
	int i = 0, value;
	float x1, x2, result;
	s.top = -1;//一般情况下,栈空时栈顶为-1
	while (a[i] != NULL) {

		if (a[i] != ' ' && a[i] >= '0' && a[i] <= '9') {
			value = 0;
			while (a[i] != ' ') {//判断该数为几位数

				value = 10 * value + a[i] - '0';//将字符转化为整数进行计算
				i++;
			}
			s.top++;
			s.data[s.top] = value;//判断所求数字的具体之后,再入栈,即压入所得数据
		}
		else {
			switch (a[i]) {//进行+,-,*,/ 以及^的运算


			case '+':
				x1 = s.data[s.top--];
				x2 = s.data[s.top--];
				result = x1 + x2;        //计算x1+x2
				s.data[++s.top] = result;//同上,压入所得的数据
				break;
			case '-':
				x1 = s.data[s.top--];
				x2 = s.data[s.top--];
				result = x2 - x1;
				s.data[++s.top] = result;
				break;
			case '*':
				x1 = s.data[s.top--];
				x2 = s.data[s.top--];
				result = x1 * x2;
				s.data[++s.top] = result;
				break;
			case '/':
				x1 = s.data[s.top--];
				x2 = s.data[s.top--];
				result = x2 / x1;
				s.data[++s.top] = result;
				break;
			case '^':
				x1 = s.data[s.top--];
				x2 = s.data[s.top--];
				result = pow(x2, x1); //pow(a,b)函数表示以a为底数的b次方<数学函数,需要导入math.h头文件>
				s.data[++s.top] = result;
				break;
			}
			i++;//继续遍历
		}
	}
	if (!s.top != -1) {
		result = s.data[s.top];
		s.top--;
		if (s.top == -1)
			return result;
		else {  //exit(-1);
			printf("----------表达式错误,请重新输入!-----------");
			
		}
	}
}


void TranslateExpress(char str[], char exp[]) {//中缀表达式转后缀表达式
	stack s;
	char ch, e{};
	int i = 0, j = 0;
	InitStack(&s);
	ch = str[i++];
	while (ch != '\0') {

		switch (ch) {

		case '(':
			Push(&s, ch);//在栈s已经存在的情况下,插入元素ch为新的栈顶元素
			break;
		case ')':
			while (GetTop(s, &e) && e != '(') {//遍历,在栈s已经存在而且非空,返回栈顶的元素e,而且不修改栈顶指针,同时禁止再出现‘(’

				Pop(&s, &e);//在栈s已经存在而且非空的情况下,删除s的栈顶元素,并用e返回其值
				exp[j++] = e;//继续遍历
			}
			Pop(&s, &e);
			break;
		case '+':
		case '-':
			while (!StackEmpty(s) && GetTop(s, &e) && e != '(') {//注意s应当不是空栈

				Pop(&s, &e);
				exp[j++] = e;
			}
			Push(&s, ch);
			break;
		case '*':
		case '/':
			while (!StackEmpty(s) && GetTop(s, &e) && e == '/' || e == '*' || e == '^') {
				Pop(&s, &e);
				exp[j++] = e;
			}
			Push(&s, ch);
			break;
		case '^':
			while (!StackEmpty(s) && GetTop(s, &e) && e == '^') {

				Pop(&s, &e);
				exp[j++] = e;
			}
			Push(&s, ch);
			break;
		case ' '://中间不允许输入空格
			break;
		default://出现错误的处理办法
			while (ch >= '0' && ch <= '9') {
				exp[j++] = ch;
				ch = str[i++];
			}
			i--;
			exp[j++] = ' ';
		}
		ch = str[i++];
	}
	while (!StackEmpty(s)) {//将剩余的内容全部出栈,此时完成所有的后缀表达式

		Pop(&s, &e);
		exp[j++] = e;
	}
	exp[j] = NULL;//确保已经清空栈
}

bool judge_infix(char str[]) {//判断中缀表达式是否合理

	int temp = 0;
	if (str[0] == '/' || str[0] == '*')
		return false;
	if (str[strlen(str) - 1] < '0' && str[strlen(str) - 1]>'9')//strlen()计算给定的字符串长度
		return false;
	for (int i = 0; i < strlen(str); i++) {

		if (str[i] == '(') {

			if (i == 0 && (str[i + 1] == '*' || str[i + 1] == '/'))
				return false;
			else if (str[i - 1] >= '0' && str[i - 1] <= '9')
				return false;
			temp++;
		}
		else if (str[i] == ')') {


			if (i == 0)
				return false;
			else if (str[i - 1] == '+' || str[i - 1] == '*' || str[i - 1] == '-' || str[i - 1] == '/')
				return false;
			else if (str[i + 1] >= '0' && str[i + 1] <= '9')
				return false;
			temp--;
		}
	}
	if (temp == 0)
		return true;
	return false;
}

int main() {


	char a[MAXSIZE], b[MAXSIZE];
	double f;
	int flag = 0;
	printf("-------------请输入一个计算公式-----------\n");
	gets_s(a,100);
	printf("-----------------中缀表达式---------------\n%s\n", a);
	bool judge = judge_infix(a);
	if (judge == false) {

		printf("---------计算公式有误,请重新输入!----------\n");
		system("pause");
		exit(-1);
	}
	else
		TranslateExpress(a, b);
	printf("-----------------后缀表达式---------------\n %s\n", b);
	f = ComputeExpress(b);
	printf("-----------------计算结果-----------------\n %f\n", f);
	system("pause");
	return 0;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

采用顺序栈,实现一个简易计算器 的相关文章

随机推荐

  • c++字符串连接函数strcat_s

    格式 int a 100 61 0 int b 100 61 0 strcat s a b 功能 把字符数组2 b 连到字符数组1 a 后面 字符数组1必须足够大 连接前两串以 0 结束
  • Python语音合成探究(二、朗读文本的编码问题)

    语音合成时 xff0c 选取的朗读文本大多是网上收集来的TXT 文件 xff0c 有些文件会因为编码原因打开不了 xff0c 程序运行出错 如同样是 离骚 txt 文档 xff0c 用 with open 39 离骚 txt 39 as f
  • 关于Windows上的Android子系统安装

    Win11早些时候的版本公式里展示的安卓系统 Windows Subsystem for Android 简称WSA xff0c 现在可以在电脑中使用 xff0c 过了一年多的时间才想起还有个这种功能 xff0c 在安装时也是发现一些小细节
  • 大一上学期C++课程设计——学生成绩管理系统(QT项目)

    这里是一个大一的萌新 xff01 仅做学习分享 工程文件在评论区置顶 xff01 xff01 近期整理了一下大一上学期的课程设计报告作为学习总结 xff0c 使用的软件是Qt Creator xff0c 主界面效果如下图 QT具体环境如下图
  • 单片机控制直流电机(风扇)电路详解

    单片机引脚为什么无法直接控制电机或风扇 xff1f 我们在使用单片机去控制 43 5V的直流电机或者散热风扇时 xff0c 可能会有一种疑惑 xff0c 51单片机的引脚电压为 43 5V xff0c 为什么不直接用单片机引脚去驱动电机或者
  • [NOIP2002 普及组] 过河卒

    题目描述 棋盘上 AA 点有一个过河卒 xff0c 需要走到目标 BB 点 卒行走的规则 xff1a 可以向下 或者向右 同时在棋盘上 CC 点有一个对方的马 xff0c 该马所在的点和所有跳跃一步可达的点称为对方马的控制点 因此称之为 马
  • Qt学习笔记(5)

    目录 一 菜单栏 MenuBar 二 工具栏 ToolBar 三 状态栏 StatusBar 四 浮动窗口 DockWidget 五 右键菜单 六 托盘菜单 一 菜单栏 MenuBar 只能有一个 创建的最上方 菜单栏有两种方式可以创建 x
  • ftp 命令访问 ftp服务器

    服务端与客户端 登录到FTP服务器时 xff0c 你可以看到服务端的文件 xff0c 这个时候就要有一个区分 xff0c 一个是服务端 xff0c 一个是客户端 xff0c 你发起连接的这台电脑就叫做客户端 xff0c 要连接的FTP服务器
  • day13-面向对象3

    一 私有权限 封装的意义 xff1a 将属性和方法放到一起做为一个整体 xff0c 然后通过实例化对象来处理 xff1b 隐藏内部实现细节 xff0c 只需要和对象及其属性和方法交互就可以了 xff1b 对类的属性和方法增加 访问权限控制
  • 如何在Linux下安装软件,以移植安装libjpeg解码库为例(总结)

    首先 xff0c 从软件官方网站或者其它渠道获取安装软件源码包 xff0c 选择所需软件版本 xff0c 解压放到一个自定义目录下 安装Linux软件通常需要如下三个步骤 xff1a 步骤一 xff1a xff1a configure xx
  • keil5里错误怎么解决Undefined symbol STM32_Control (referred from main.o).

    解决方法 xff1a 遇见这样的问题是忘记添加 xff08 c xff09 文件了 xff0c 如果不知道添加哪个 xff0c 可以根据下面显示的错误点击转到定义文件 xff0c 和 c文件 哪个没有就是缺少哪个文件啦 xff0c 直接添加
  • Ubuntu 安装CUDA

    1 查看操作系统的发行版号和操作系统版本 uname a Linux herri01 HP Z4 G4 Workstation 5 15 0 48 generic 54 Ubuntu SMP Fri Aug 26 13 26 29 UTC
  • 用冒泡法对10个整数从小到大排序。

    第一次学冒泡排序 xff0c 给十个数进行排序 xff0c 我们用到的是冒泡法 xff0c 每次将最大的一个数放到最后 xff0c 由于前九次已经把后面的序列排好 xff0c 所以一共只需要进行九次即可 xff1b 同时在进行第i次排序的时
  • spring boot集成mybatis-plus——Mybatis Plus 批量 Insert_新增数据(图文讲解)

    Mybatis Plus 批量 Insert 新增数据 图文讲解 更新时间 2023 01 10 16 02 58 前言 大家好 xff0c 我是小哈 本小节中 xff0c 我们将学习如何通过 Mybatis Plus 实现 MySQL 批
  • python中输出函数print()的一些必要知识

    一 print基本格式 1 仅用于输出字符串 格式 xff1a print 要输入的字符串 例子 xff1a print 34 希望世界和平 34 2 仅用于输出变量 格式 xff1a print 变量1 xff0c 变量2 xff0c 例
  • 洛谷练习题——入门(顺序结构)P1001、P5703、P5704、P5705、P5706

    有感 xff1a 昨天从同学哪里接触到了洛谷这个刷题的网站 xff0c 感觉对于我这个新手很友好 xff0c 连续刷了几道题 xff0c 有点上头的感觉 xff0c 很有成就感 xff0c 虽然知道这是很简单的题 xff0c 但是对于目前的
  • C语言:字符串常用函数:

    本篇文章介绍了字符串最最最 最常用的函数 xff0c 看到的朋友们一定不要错过哦 xff0c 全是干货 xff0c 记得收藏起来 xff0c 别等想要的时候找不到了 xff01 所给的测试样例只是例子 xff0c 小伙伴们也可以自己用不同的
  • RAID5的搭建

    1 磁盘阵列raid5级别是带有校验码的条带磁盘组 xff0c 所以至少要四块磁盘 xff0c 其中一块磁盘用作存储校验码 xff0c 如下图查看当前系统中磁盘状态 xff0c 与其它阵列不同的是这个海明码可以存储在每一块磁盘中 xff0c
  • 群晖docker实现阿里云动态公网域名解析ddns服务

    日常生活中 xff0c 一般家庭用户宽带使用的都是内网ip xff0c 如果需要在外网就是远程使用 xff0c 需要将家庭ip向电信部门申请变更为公网ip xff0c 通常情况下 xff0c 我们获得的都是动态公网ip xff0c 这种ip
  • 采用顺序栈,实现一个简易计算器

    首先需要区分中缀表达式与后缀表达式 xff08 中缀转为后缀即可进行计算 xff09 xff1a 例如中缀表达式为12 43 3 6 43 2 2 15 3 那么所求的后缀表达式的步骤为 1 判断12是数字 xff0c 不入栈 xff0c