利用双栈法实现简易计算器

基于标准c++实现计算器

一.需求实现

1.实现功能

支持运算符:+,-,*,/。其他符号:()

支持数据类型:正整数(负数与小数后续实现)

2.实现方法

符号优先等级处理方法:符号等级制

运算式表达式处理方法:双栈法

二 双栈法实现表达式计算思路

设计两个栈来分别储存运算符和数字,运算符栈用‘#’表示开始与结束
让运算符和数字依次入栈
出栈规则:当前入栈的运算符比栈顶的运算符优先级

总的来说就是有括号先算括号内,算完括号内再算整体

例:12+(2*3+5)

        输入:#12+(2*3+5)#

数字栈符号栈过程
#扫描字符串得到#,将其压入symbol栈
1扫描字符串得到1,将其压入number栈
12扫描字符串得到2,将其压入number栈
12#+扫描字符串得到+,将其压入symbol栈
12#+(扫描字符串得到(,'('优先级大于‘+’,将‘(’压入symbol栈
122#+(扫描字符串得到2,将其压入number栈
122#+(*扫描字符串得到*,'*'优先级小于‘(’,但通过代码将‘(’后的符号的优先级高于‘(’,将'*'压入symbol栈
1223#+(*扫描字符串得到3,将其压入number栈
126#+(+扫描字符串得到+,'+'优先级小于将‘*’,将'*'从symbol栈弹出,数字栈弹出两个数2/3,2与3运算得到6,6压入number栈,'+'压入symbol栈
1265#+(+扫描字符串得到5,将其压入number栈
12 11#+扫描字符串得到')',')'优先级小于将‘+’,将'+'从symbol栈弹出,数字栈弹出两个数6/5,6与5运算得到11,11压入number栈,'('弹symbol栈
23#扫描字符串得到'#',‘#’是终止符,将'+'从symbol栈弹出,数字栈弹出两个数12/11,12与11运算得到23,23压入number栈

三 实现代码

1.运算优先级功能实现

(1)运算符号等级 

int SymbolPri(char sym)	//量化符号优先级
{
	switch (sym)
	{
	case '#': return 0;
	case ')': return 1;
	case '+': 
	case '-': return 2;
	case '/': 
	case '*': return 3;
	case '(': return 4;
	default:return -1;
	}
}

(2)运算优先级的获取

int PreOrder(char sym1, char sym2)	//比较两个符号的优先级
{
	int i = SymbolPri(sym1);	// i为即将入栈的符号,j为栈顶符号
	int j = SymbolPri(sym2);
	if (sym2 == '(')	//( )内的 + - * / 还能进栈但是 + - * / 对应的数字小于 ( 对应的数字 所以把这里设置成 1 让()内的 + - * / 可以进栈 
		return 1;
	if (i == -1 || j == -1)
		return -1;
	if (i > j)
		return 1;
	else if (i == j)
		return 0;
	else
		return -1;
}

2.运算表达式处理并计算

int Calculate(char* s)
{
	int x;	
	bool flag = false;	//标志位,判断两栈是否为空
	stack<char> symbol;	//符号栈
	char c;	//用来保存symbol栈顶的数据 
	stack<int>	number;	//数字栈
	int num1, num2, num;	//num1/num2用来保存数字栈栈顶的数字   num 用来压入数据 
	symbol.push('#');
	number.push(1);
	cout << '#' << "is pushed1" << endl;
	char* p = s;	//输入缓存到char *p中
	while (*p != '#')	
	{
		if (isNumber(p))	//碰到数字
		{
			p = getNum(p, num);
			number.push(num);
			cout << num << "is pushed2" << endl;
		}
		else   //碰到符号
		{
			c = symbol.top();
			if (PreOrder(*p, c) > 0)	//判断符号优先级 要入栈符号优先级大于栈顶符号
			{
				symbol.push(*p);
				cout << *p << "is pushed3" << endl;
			}
			else   //要入栈符号优先级小于栈顶符号 弹出栈顶符号,数字栈弹出两个数字,进行计算
			{
				symbol.pop();
				cout << c << "is pushed4" << endl;
				num1 = number.top();
				number.pop();	
				cout << num1 << "is poped5" << endl;
				num2 = number.top();
				number.pop();
				cout << num2 << "is poped6" << endl;
				x = express(num2, num1, c);
				number.push(x);	//计算结果压入数字栈中
				cout << x << "is pushed7" << endl;
				if ((*p == '+') || (*p == '-') || (*p == '*') || (*p == '/'))	//计算完后符号p为+-*/继续压入栈中
				{
					symbol.push(*p);
					cout << *p << "is pushed8" << endl;
				}
				if (*p == ')')
				{
					c = symbol.top();
					if (c != '(')
					{
						c = symbol.top();
						symbol.pop();
						num1 = number.top();
						number.pop();
						cout << num1 << "is poped9" << endl;
						num2 = number.top();
						number.pop();
						cout << num2 << "is poped10" << endl; 
						x = express(num2, num1, c);
						number.push(x);
						cout << x << "is pushed11" << endl;
						c = symbol.top();
						symbol.pop();
						cout << c << "is poped12" << endl;
					}
					else     //c = '('
					{		
						symbol.pop();
						cout << c << "is poped13" << endl;
					}
				}
			}
			
		}
		p++;
	}
	if (*p == '#')
	{
		c = symbol.top();
		symbol.pop();
		cout << c << "is poped14" << endl;
		num1 = number.top();
		number.pop();
		cout << num1 << "is poped15" << endl;
		num2 = number.top();
		number.pop();
		cout << num2 << "is poped16" << endl;
		x = express(num2, num1, c);
		cout << x << "is pushed17" << endl;
		number.push(x);
		c = symbol.top();
		while (c != '#')
		{
			c = symbol.top();
			symbol.pop();
			cout << c << " is poped18" << endl;
			num1 = number.top();
			number.pop();
			cout << num1 << " is poped19" << endl;
			num2 = number.top();
			number.pop();
			cout << num2 << " is poped20" << endl;
			x = express(num2, num1, c);
			number.push(x);
			cout << x << " is pushed21" << endl;
			c = symbol.top();
			symbol.pop();
			cout << c << "is poped22" << endl;
		}
		num = number.top();
		number.pop();
		cout << "结果是:" << num << endl;
		return num;
	}
}

四.完整代码

#include<iostream>
#include<stack>
using namespace std;

int SymbolPri(char sym)	//量化符号优先级
{
	switch (sym)
	{
	case '#': return 0;
	case ')': return 1;
	case '+': 
	case '-': return 2;
	case '/': 
	case '*': return 3;
	case '(': return 4;
	default:return -1;
	}
}

int PreOrder(char sym1, char sym2)	//比较两个符号的优先级
{
	int i = SymbolPri(sym1);	// i为即将入栈的符号,j为栈顶符号
	int j = SymbolPri(sym2);
	if (sym2 == '(')	//( )内的 + - * / 还能进栈但是 + - * / 对应的数字小于 ( 对应的数字 所以把这里设置成 1 让()内的 + - * / 可以进栈 
		return 1;
	if (i == -1 || j == -1)
		return -1;
	if (i > j)
		return 1;
	else if (i == j)
		return 0;
	else
		return -1;
}

bool isNumber(char* p)	//判断输入字符是数字或符号
{
	if (*p >= '0' && *p <= '9')
		return true;
	else
		return false;
}

char* getNum(char* p, int& num)	//将数字字符转化为数字
{
	num = 0;
	while (isNumber(p))
	{
		num = 10 * num + (*p - '0');
		p++;
	}
	p--;	//???????
	return p;
}

int express(int num1, int num2, char sym)	//运算法则
{
	cout << num1 << sym << num2 << "is calculatded" << endl;
	switch (sym)
	{
	case '+':return num1 + num2;
	case '-':return num1 - num2;
	case '*':return num1 * num2;
	case '/':return num1 / num2;
	default:cout << "wrong" << endl;
	}
}

int Calculate(char* s)
{
	int x;	
	bool flag = false;	//标志位,判断两栈是否为空
	stack<char> symbol;	//符号栈
	char c;	//用来保存symbol栈顶的数据 
	stack<int>	number;	//数字栈
	int num1, num2, num;	//num1/num2用来保存数字栈栈顶的数字   num 用来压入数据 
	symbol.push('#');
	number.push(1);
	cout << '#' << "is pushed1" << endl;
	char* p = s;	//输入缓存到char *p中
	while (*p != '#')	
	{
		if (isNumber(p))	//碰到数字
		{
			p = getNum(p, num);
			number.push(num);
			cout << num << "is pushed2" << endl;
		}
		else   //碰到符号
		{
			c = symbol.top();
			if (PreOrder(*p, c) > 0)	//判断符号优先级 要入栈符号优先级大于栈顶符号
			{
				symbol.push(*p);
				cout << *p << "is pushed3" << endl;
			}
			else   //要入栈符号优先级小于栈顶符号 弹出栈顶符号,数字栈弹出两个数字,进行计算
			{
				symbol.pop();
				cout << c << "is pushed4" << endl;
				num1 = number.top();
				number.pop();	
				cout << num1 << "is poped5" << endl;
				num2 = number.top();
				number.pop();
				cout << num2 << "is poped6" << endl;
				x = express(num2, num1, c);
				number.push(x);	//计算结果压入数字栈中
				cout << x << "is pushed7" << endl;
				if ((*p == '+') || (*p == '-') || (*p == '*') || (*p == '/'))	//计算完后符号p为+-*/继续压入栈中
				{
					symbol.push(*p);
					cout << *p << "is pushed8" << endl;
				}
				if (*p == ')')
				{
					c = symbol.top();
					if (c != '(')
					{
						c = symbol.top();
						symbol.pop();
						num1 = number.top();
						number.pop();
						cout << num1 << "is poped9" << endl;
						num2 = number.top();
						number.pop();
						cout << num2 << "is poped10" << endl; 
						x = express(num2, num1, c);
						number.push(x);
						cout << x << "is pushed11" << endl;
						c = symbol.top();
						symbol.pop();
						cout << c << "is poped12" << endl;
					}
					else     //c = '('
					{		
						symbol.pop();
						cout << c << "is poped13" << endl;
					}
				}
			}
			
		}
		p++;
	}
	if (*p == '#')
	{
		c = symbol.top();
		symbol.pop();
		cout << c << "is poped14" << endl;
		num1 = number.top();
		number.pop();
		cout << num1 << "is poped15" << endl;
		num2 = number.top();
		number.pop();
		cout << num2 << "is poped16" << endl;
		x = express(num2, num1, c);
		cout << x << "is pushed17" << endl;
		number.push(x);
		c = symbol.top();
		while (c != '#')
		{
			c = symbol.top();
			symbol.pop();
			cout << c << " is poped18" << endl;
			num1 = number.top();
			number.pop();
			cout << num1 << " is poped19" << endl;
			num2 = number.top();
			number.pop();
			cout << num2 << " is poped20" << endl;
			x = express(num2, num1, c);
			number.push(x);
			cout << x << " is pushed21" << endl;
			c = symbol.top();
			symbol.pop();
			cout << c << "is poped22" << endl;
		}
		num = number.top();
		number.pop();
		cout << "结果是:" << num << endl;
		return num;
	}
}
int main()
{
	char mychar[100];
	cin.getline(mychar, 50);	//#作为终止符
	cout << Calculate(mychar) << endl;
	return 0;
}

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值