实验6 栈——算术表达式

文章描述了一个使用栈来计算数学表达式的程序设计问题。首先定义了一个数组栈模板类,然后通过读取输入的数学表达式,识别数字和运算符,利用栈的特性处理运算符的优先级,最终计算出表达式的值。程序处理了负数和多位数的情况,并确保结果保留两位小数。
摘要由CSDN通过智能技术生成

实验6 栈——算术表达式

注意

因为精度问题,请使用double存数据。

要求

  1. 创建栈类,采用数组描述;
  2. 计算数学表达式的值。
    输入数学表达式,输出表达式的计算结果。数学表达式由单个数字和运算符+-*/() 构成,例如 2+3*(4+5)-6/4。假定表达式输入格式合法。

格式

输入

第一行一个整数n(1<=n<=100),代表表达式的个数。
接下来n行,每行一个表达式,保证表达式内的数字为单个整数,表达式内各运算符和数字间没有空格,且表达式的长度不超过2000。

输出

每行表达式输出一个浮点数,要求保留两位小数,保证输入表达式合法。

思路与探讨

笔记补充——第八章:栈

整体思路描述

  • 首先定义一个数组栈,定义并实现构造函数、出栈、入栈的相关函数;

  • 然后定义运算,原理即将数字栈的前两个数和符号栈栈顶元素取出做一次运算,并将结果压入数字栈

  • 最后定义功能函数,即实现字符串读取,识别数字和字符并进行相关运算。

细节思路补充

  • 运算符读取时关注先乘除后加减

  • 负数判断?

    开一个 judge 标记。识别符号,将 judge 标记为 true。再读取该符号后的数值后对其作取负操作,具体如下:

    if((i == 0||s[i-1] == '(')&& s[i] =='-')
    {
    	judge = true;//负数标记
    	continue;
    }
    
    if(judge)
    {
    	value = -value;//负数处理
    	judge = false;//变回来,之后遇到"-"再次变换
    }
    
  • 多位数处理?

    while(s[i+1] >= '0' && s[i+1] <= '9')
    {
    	value = 10 * value + (s[i+1]-'0');
    	i++;
    }
    

若已看懂思路,试着自己写~


实现代码

#include<iostream>
#include<string>
#include <iomanip>
using namespace std;

//定义一个数组栈 
template<class T>
class arraystack
{
	public:
		arraystack(int initialCapacity = 10);//构造函数 
		~arraystack(){delete [] stack;}//析构函数 
		bool empty() const {return stackTop == -1;}
		int size() const {return stackTop + 1;}
		T& top()
		{
			if(stackTop == -1)
				exit(1);
			return stack[stackTop]; 
		}
		void pop();//出栈 
		void push(const T& theElement);//入栈 
	private:
		int stackTop;//当前栈顶 
		int stackLength;//栈容量 
		T *stack;//元素数组 
};

template<class T>
arraystack<T>::arraystack(int initialCapacity)
{//构造函数 
	if(initialCapacity < 1)
		exit(1);
	stackLength = initialCapacity;
	stack = new T[stackLength];
	stackTop = -1;
 } 
 
template<class T>
void arraystack<T>::pop()
{//出栈 
	if(stackTop == -1)
		exit(1);
	stack[stackTop--].~T();//T的析构函数 
}

template<class T>
void arraystack<T>::push(const T& theElement)
{//入栈 
	if(stackTop == stackLength - 1)
	{//容量满后的容量扩充 
		stackLength *= 2;//将栈的容量扩充二倍 
		T newStack[stackLength];
		for(int i = 0;i < stackLength;i++)
		{
			newStack[i] = stack[i];
		}
		delete stack;
		stack = newStack;	
	}
	stack[++stackTop] = theElement;
}

//定义运算
//原理:将数字栈的前两个数和符号栈栈顶元素取出做一次运算,并将结果压入数字栈 
void calculate(arraystack<double> &number, arraystack<char>&symbol)
{
	double a,b;
	
	//取出数字栈的前两个数
	a = number.top();//取出数字栈第一个数   
	number.pop();//弹出栈顶元素,这样才能取第二个 
	b = number.top();//取出当前数字栈第一个数  
	number.pop();//弹出栈顶元素 
	
	//取符号栈栈顶元素,且根据符号栈的栈顶元素不同进行不同运算
	switch(symbol.top())
	{ 
		case '+':
			number.push(a+b);
			break;
		case '-':
			//算术里先读取的在下方,所以是b-a 
			number.push(b-a);
			break;
		case '*':
			number.push(a*b);
			break;
		case '/':
			//算术里先读取的在下方,所以是b/a 
			number.push(b/a);
			break;	
		default:break;
	}
	symbol.pop();//将运算完的符号弹出栈 
}

void function(string s,int length) 
{//功能实现 
	bool judge = false;
	arraystack<double> number(length);//声明一个数字栈 
	arraystack<char> symbol(length);//声明一个字符栈 
	for(int i = 0;i < length;i++)//遍历输入的表达式 
	{
		if(s[i] == ' ') continue;//如果输入的如果是空格,跳过 
		if(s[i] >= '0'&&s[i] <= '9')
		{//读到的数字 
			int value = s[i]-'0';//把字符转化为运算数值 
			while(s[i+1] >= '0'&&s[i+1] <= '9')
			{//多位数处理 
				value = 10 * value + (s[i+1]-'0');
				i++;
			}
			if(judge){
				value = -value;//负数处理 
				judge = false;//变回来,之后遇到"-"再次变换 
			}
			number.push(value);
		}
		else
		{//读到的是字符 
			if((i == 0||s[i-1] == '(')&& s[i] =='-') 
			{
				judge = true;//负数标记 
				continue;
			}
			switch(s[i])
			{
				//加减运算 
				case '+':
				case '-':
					if(symbol.empty()||symbol.top() == '(') symbol.push(s[i]);  
					else
					{
						//不管那个字符是啥,先算了,让那个字符pop掉 
						calculate(number,symbol);  
						//pop掉一个可能还有一个,继续calculate,把已经有的能运算的先用了 
						if(!symbol.empty() && symbol.top() != '(') calculate(number,symbol);
						symbol.push(s[i]);
					}
					break;
				//乘除运算	
				case '*':
				case '/':
					if(symbol.empty()||symbol.top() == '(') symbol.push(s[i]);
					//先乘除,后加减 
					else if(symbol.top() == '+'||symbol.top() == '-') symbol.push(s[i]); 
					else if(symbol.top() == '*'||symbol.top() == '/')
					{
						calculate(number,symbol);
						symbol.push(s[i]);
					} 				
					break;
				case '('://左括号直接入栈 
					symbol.push(s[i]);
					break;
				case ')'://遇到右括号 ,对括号内运算直至运算到左括号 
					while (symbol.top()!='(') 
					{
					    calculate(number,symbol);
					}
					symbol.pop();//将左括号弹出栈 
					break;
				default:break;
			}
		}
	}
	while(!symbol.empty()) calculate(number,symbol);
		cout<<setprecision(2)<<fixed<<number.top()<<endl;//精度控制,保留两位小数 
}

int main()
{
	int n;
	cin >> n;
	for(int i = 0;i < n;i++)
	{
		//将输入的表达式存到一个字符串中 
		string str;    
		//记录字符串长度          
		int length;           
		cin >> str; 
		length = str.length();	
    	function(str,length);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

啦啦右一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值