利用栈实现计算器功能-C语言

2023-05-16

功能: 实现计算器,可以运算带括号的表达式。
如1+(1+1)*2+1

首先,我们需要了解中缀表达式和后缀表达式。

中缀表达式(符号在中间):
如1+(1+1)*2+1

后缀表达式(符号在后面):
如上会得到1 1 1 + 2 * + 1 +

步骤:
①从左往右,若遇到数字先放一边,遇到符号就进栈。
②若栈顶是“(”,接下来符号肯定进栈;若接下来遇到“)”,“)”不进栈,将符号从栈里取出,直到遇到“)”,将“)”删除。若接下来符号优先级比栈顶高则进栈,若低则取出栈顶,新符号进栈。
③将栈内最后符号出栈后,这个表达式就是后缀表达式。
④接下来从左往右遇到数字就进栈,遇到符号则将栈顶和栈顶下一个元素进行该符号运算,后出来的运算前一个,得值再进栈。
⑤最后栈内元素就是数值大小。

图例:
在这里插入图片描述

在这里插入图片描述
为了方便快速计算,我们使用两个栈。
在这里插入图片描述
运算数:
 直接进栈
运算符:
 进栈
  空栈 || 优先级高 || 栈顶是“(”并且表达式不是“)”
 出栈不计算
  栈顶是“(”同时是表达式是“)”
 出栈计算
  表达式优先级不高于栈顶 || 表达式是“)”同时栈顶不是“(” || 表达式为空但是栈不为空

计算1 * (1 + 1 ) * 2+1 * 2
在这里插入图片描述
main.c

/*
程序功能:实现计算器,可以运算带括号的表达式。
编程环境:Dev-C++
程序模块:main.c/linkstack.c/linkstack.h
*/
#include "linkstack.h"

int Priority(char ch)
{
	switch(ch)
	{
		case '(':
			return 3;
		case '*':
			return 2;
		case '/':
			return 2;
		case '+':
			return 1;
		case '-':
			return 1;
		default:
			return 0;
	}
}

int main()
{
	Stack s_num,s_opt;	//定义数字栈、符号栈  
	
	if (InitStack(&s_num) == FAILURE || InitStack(&s_opt) == FAILURE)
	{
		printf("初始化失败!\n");
		return -1;
	}
	
	char opt[128] = {0};
	int i = 0, tmp = 0, num1, num2;
	
	printf("请输入表达式:\n");
	scanf("%s", opt);
	
	while (opt[i] != '\0' || EmptyStack(&s_opt) != SUCCESS) //表达式不为空或栈不为空就继续 
	{
		if (opt[i] >= '0' && opt[i] <= '9')	//若下位是数字,求出asc码 
		{
			tmp = opt[i] - '0';
			i++;
			if (opt[i] < '0' || opt[i] > '9')	//若下位不是数字,将tmp入栈;若下位是数字继续循环 
			{
				push(&s_num, tmp);
				tmp = 0;
			}
		}
		else	//操作符 
		{
			if (EmptyStack(&s_opt) == SUCCESS || Priority(opt[i]) > Priority(GetTop(&s_opt)) ||
				(GetTop(&s_opt) == '(') && (opt[i] != ')'))
			{
				push(&s_opt, opt[i]);
				i++;
				continue;	
			}
			
			if (GetTop(&s_opt) == '(' && opt[i] == ')')  
			{
				pop(&s_opt);
				i++;
				continue;
			}
			
			//此处可直接用else判断 
			if (Priority(opt[i]) <= Priority(GetTop(&s_opt)) || ((opt[i] == ')') && GetTop(&s_opt) != ')') ||
				opt[i] == '\0' && EmptyStack(&s_opt) != SUCCESS)
			{
				switch(pop(&s_opt))
				{
					case '+':
						num1 = pop(&s_num);
						num2 = pop(&s_num);
						push(&s_num, num1 + num2);
						break;
					case '-':
						num1 = pop(&s_num);
						num2 = pop(&s_num);
						push(&s_num, num2 - num1);
						break;
					case '*':
						num1 = pop(&s_num);
						num2 = pop(&s_num);
						push(&s_num, num1 * num2);
						break;
					case '/':
						num1 = pop(&s_num);
						num2 = pop(&s_num);
						push(&s_num, num2 / num1);
						break;
				}
			}
		}
	}
	printf("%d\n", GetTop(&s_num));
	
	return 0;
}

linkstack.c

#include "linkstack.h"

int InitStack(Stack *s)
{
	if (NULL == s)
	{
		return FAILURE;
	}
	
	s->top = NULL;
	s->length = 0;	//表示空栈 
	
	return SUCCESS;
}

int push(Stack *s, int num)
{
	if (NULL == s)
	{
		return FAILURE;
	}
	
	Node *n = (Node *)malloc(sizeof(Node) * 1);
	if (NULL == n)
	{
		return FAILURE;
	}
	
	n->data = num;
	n->next = s->top;
	s->top = n;	//更新栈顶指针 
	s->length++;
	
	return SUCCESS;
}

int GetTop(Stack *s)
{
	if (NULL == s)
	{
		return FAILURE;
	}
	
	if (s->top == NULL)
	{
		return FAILURE;
	}
	
	return s->top->data;
}

int pop(Stack *s)
{
	if (NULL == s)
	{
		return FAILURE;
	}
	
	if (s->top == NULL)	//空栈不能出栈 
	{
		return FAILURE;
	}
	
	Node *n = s->top;
	int data = n->data;
	s->top = n->next;
	free(n);
	s->length--;

	return data;
}

int EmptyStack(Stack *s)
{
	if (NULL == s)
	{
		return FAILURE;
	}
	
	return (s->top == NULL) ? SUCCESS : FAILURE;
}

linkstack.h

#ifndef LINKSTACK_H
#define LINKSTACK_H

#include <stdio.h> 
#include <stdlib.h>

#define SUCCESS 1000
#define FAILURE 1001

struct Node	//表示结点信息 
{
	int data;
	struct Node *next;
};
typedef struct Node Node;

struct Stack	//表示栈信息 
{
	Node *top;
	int length;
};
typedef struct Stack Stack;

int InitStack(Stack *stack);
int push(Stack *s, int num);
int GetTop(Stack *s);
int pop(Stack *s);
int EmptyStack(Stack *s);
 
#endif

实现效果
在这里插入图片描述

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

利用栈实现计算器功能-C语言 的相关文章

随机推荐

  • 各种常用的默认端口号 总结

    各种常用的默认端口号 总结 端口号的范围是从1 xff5e 65535 其中1 xff5e 1024是被RFC 3232规定好了的 xff0c 被称作 众所周知的端口 Well Known Ports xff1b 从1025 xff5e 6
  • 利用hdparm工具配合crontab使硬盘不用时休眠

    背景 xff1a 上次搞定了硬盘的自动挂载问题 xff0c 回头购入了个功率测试仪 xff0c 发现树莓派取消挂载移动硬盘后 xff0c 硬盘依然不能自动休眠 我用的是一个两盘位硬盘盒做RAID1 xff0c 运行两个3 5的2T硬盘功耗大
  • C++学习笔记

    一 基于过程的程序设计 1 1 概念及基础 pragma once 防止头文件重复包含 自定义的头文件用 34 34 xff0c 系统的用 lt gt 在标准输入流与输出流中使用控制符需要添加 include iomanip头文件 C 43
  • JAVA学习笔记

    第一章 IDEA基本配置和快捷键 IDEA快捷键 快捷键功能shift 43 F6选中目标内容后 xff0c 更改所有用到它的内容ctrl 43 Y删除当前行ctrl 43 D复制当前行Alt 43 Enter导入包自动修正代码Ctrl 4
  • 动态规划——装箱问题

    使用动态规划 xff0c dp i 记录当容积为i时的最大填充体积 span class token keyword import span java span class token punctuation span util span
  • 两种经典最短路径算法

    dijkstral算法 xff1a 计算单源最短路径 xff08 固定起点 xff0c 计算出起点到其他所有顶点的最短路径 xff09 用贪心思想 xff0c 每次找出距离起点最近的节点 xff0c 直到找出所有节点动态规划 xff1a 每
  • 【Spring Boot组件集成实战】集成Kaptcha谷歌验证码

    更多精彩内容 xff0c 请访问 Spring Boot组件集成实战专栏 xff01 推荐项目 xff1a 一套基于Spring Boot 43 Layui的内容管理系统 快速开发脚手架 xff08 含完整的开发文档 演示网址等 xff09
  • Redis

    NoSQL数据库 概述 NoSQL数据库 xff0c 指的是非关系型的数据库 不依赖业务逻辑的方式存储 xff0c 而是以简单的key value模式存储 因此大大增加了数据库的扩展能力 不遵循SQL标准不支持ACID 原子性 xff1a
  • 动态规划之戳气球

    leetcode312 戳气球 这一题可以用动态规划来解决 但是dp含义的设置和状态转移方程的设计很有意思 首先 一维dp难以实现的 xff0c 应该考虑二维dp xff0c 尤其在一个数组中 xff0c 要考虑到双指针移动来解决复杂问题
  • Java正则表达式

    捕获组 span class token keyword public span span class token keyword static span span class token keyword void span span cl
  • 进程同步与互斥

    什么是进程同步 答 xff1a 进程同步指的是 xff0c 由于进程并发执行具有异步性 xff08 即各自以独立地 不可预知的速度向前推进 xff09 xff0c 但是某些情况下又需要进程之间进行配合和协调来完成一项工作 xff08 存在执
  • maven项目clean,Some problems were encountered while building the effective model for

    maven项目点击clean出现问题 xff1a Some problems were encountered while building the effective model for com whgk robotclient jar
  • linux常用命令(五)解压缩、软件包安装

    解压缩 tar xff1a c xff1a 打包 t xff1a 显示内容目录 x xff1a 解压 z xff1a 使用zip gzip压缩 v xff1a 显示详细信息 f xff1a 指定文件 tar cf xx tar file x
  • 配置阿里云的CDN加速

    1 控制台中找到CDN的控制台 需要开通 xff0c 按流量 按带宽都可以 2 添加域名 在 39 域名管理中 39 39 添加域名 39 3 修改域名的DNS 添加域名管理后 xff0c 会产生一个cname值 xff0c 将原来域名的d
  • openssl升级时,libssl.so.10缺失问题

    openssl升级时 xff0c 造成了动态库的缺失 xff0c wget yum命令都不能正常使用 报错 xff1a error while loading shared libraries libcrypto so 1 0 0 cann
  • Python的类定义,实例化

    定义 xff1a 必须使用class关键字 类名必须是用大驼峰命名 类定义完成后 xff0c 就会产生一个类对象 xff0c 绑定到了标识符ClassName上 class ClassName 语句块 举例 xff1a class MyCl
  • iOS开发,引入第三方库,秒验,XCBBuildService崩溃,问题解决

    之前使用秒验SDK都是直接引入 xff0c 便可使用 xff0c 今天引入后 xff0c XCBBuildService意外退出 尝试各种方法都不可以 于是使用CocoaPods引入第三方库 xff0c 终于可以运行 xff0c 但是仍然报
  • 【Spring Boot组件集成实战】集成MyBatis-Plus-Generator代码生成器(Version 3.5.1+)

    更多精彩内容 xff0c 请访问 Spring Boot组件集成实战专栏 xff01 推荐项目 xff1a 一套基于Spring Boot 43 Layui的内容管理系统 快速开发脚手架 xff08 含完整的开发文档 演示网址等 xff09
  • Ansible的安装与使用

    Ansible的安装 1 安装源 yum search ansible yum y install centos release ansible 29 2 安装ansible yum y install ansible 3 添加被管理服务器
  • 利用栈实现计算器功能-C语言

    功能 xff1a 实现计算器 xff0c 可以运算带括号的表达式 如1 43 xff08 1 43 1 xff09 2 43 1 首先 xff0c 我们需要了解中缀表达式和后缀表达式 中缀表达式 xff08 符号在中间 xff09 xff1