算法表达式求值演示(栈的应用)

【问题描述】
表达式计算是实现程序设计语言的基本问题之一,也是栈的应用的一个典型例子。设计一个程序,演示用算符优先法对算术表达式求值的过程。
【实现要求】
(1) 以字符序列的形式从终端输入语法正确的、不含变量的整数表达式。利用下表给出的算符优先关系,实现对算术混合运算表达式的求值,并仿照求值中运算符栈、运算数栈、输入字符和主要操作的变化过程。
(2) 扩充运算符集,如增加乘方、单目减、赋值等运算。
(3) 计算器的功能和仿真界面(选作)。
【测试数据】
下列表达式:
3*(7-2); 8; 1+2+3+4; 88-15; 1024/48; 1024/(48); (20+2)(6/2);
3-3-3; 8/(9-9); 2*(6+2*(3+6*(6+6))); (((6+6)*6+3)*2+6)*2;
【实现提示】
(1) 设置运算符栈和运算数栈辅助分析算符优先关系。
(2) 在读入表达式的字符序列的同时,完成运算符和运算数(整数)的识别处理,以及相应的运算。
(3) 在识别出运算数的同时,要将其字符序列形式转换成整数形式。
(4) 在程序的适当位置输出运算符栈、运算数栈、输入字符和主要操作的内容。

实现思路:
主要使用的是栈的结构。程序实现一共分为两步:第一步,将输入的表达式转化为计算机方便处理的后缀表达式,;第二步,计算后缀表达式。
其中第一步,使用了两个栈:操作符存储栈(op)以及后缀表达式存储栈(postexp)。而第二步,则是通过一个辅助栈,结合后缀表达式存储栈(postexp)即主栈,分别对每个操作符以及对应得操作数进行计算,计算完成后再将其压入主栈,最后当整个表达式计算完成后再将最后结果弹出,并输出。
在处理单目操作符:“++”与“–”将其转为“a”与“s”方便进行处理。
操作:
直接输入表达式,再输入“enter”即可得到表达式的结果,会忽略空格。

main.cpp


#include<iostream>
#include<string>
#include<stdlib.h>
#include"stack.h"
#include<Windows.h>

using namespace std;


char Precede(char a, char b) {
	int i, j;
	char pre[][10] = {
		/*运算符之间的优先级制作成一张表格*/
		{ '>','>','<','<','<','>','<','<','<','>' },
		{ '>','>','<','<','<','>','<','<','<','>' },
		{ '>','>','>','>','<','>','<','<','<','>' },
		{ '>','>','>','>','<','>','<','<','<','>' },
		{ '<','<','<','<','<','>','<','<','<','0' },
		{ '>','>','>','>','0','=','>','>','>','>' },
		{ '>','>','>','>','<','>','>','<','<','>' },
		{ '>','>','>','>','<','>','>','>','>','>' },
		{ '>','>','>','>','<','>','>','>','>','>' },
		{ '<','<','<','<','<','0','<','<','<','=' } };
	switch (a) {
	case '+': i = 0; break;
	case '-': i = 1; break;
	case '*': i = 2; break;
	case '/': i = 3; break;
	case '(': i = 4; break;
	case ')': i = 5; break;
	case '^': i = 6; break;
	case 'a': i = 7; break;//用a代替++符号方便处理
	case 's': i = 8; break;//用s代替--符号方便处理
	case '#': i = 9; break;
	}
	switch (b) {
	case '+': j = 0; break;
	case '-': j = 1; break;
	case '*': j = 2; break;
	case '/': j = 3; break;
	case '(': j = 4; break;
	case ')': j = 5; break;
	case '^': j = 6; break;
	case '++': j = 7; break;
	case '--': j = 8; break;
	case '#': j = 9; break;
	}
	return pre[i][j];
}

int tranNum(stackL *postexp, string exp, int i)//将中缀表达式中的多位数,按照从低位到高位顺序压入postexp栈中,方便后续计算
{
	int len = 0,j;
	char expRead = exp[i];
	while (expRead <= '9'&&expRead >= '0')//获得数符长度
	{
		//PushL(postexp, expRead);
		i++;
		expRead = exp[i];
		len++;
	}
	for (j = i-1; j >= i - len;j--)
	{
		PushL(postexp, exp[j]);
	}
	i--;			//使i恰好下次循环指向非数字
	PushL(postexp, '#');
	return i;
}
void tranPost(stackL *op, stackL*postexp, string exp)//将中缀表达式转化为后缀表达式
{
	int i;
	char expRead, tempChar,preOp;
	InitStackL(op);
	InitStackL(postexp);
	PushL(op, '#');
	PushL(postexp, '#');

	for (i = 0; i < (int)exp.length(); i++)
	{
		expRead = exp[i];
		
		if (expRead == '#')				//表达式尾端
			break;
		else if (expRead == ' ')		//忽略空格
			continue;
		else if (expRead <= '9'&&expRead >= '0')	//处理操作数,传入i,postexp,exp,返回i
		{
			i = tranNum(postexp, exp, i);
		}
		else if (expRead != '(' && expRead != ')' && expRead == exp[i + 1])//处理单目运算符(++、--)
		{
			if (expRead == '+')
				PushL(op, 'a');
			else if (expRead == '-')
				PushL(op, 's');
			else
			{
				cout << "error\n";
				break;
			}
			i++;									//使遍历跳过自增自减符号到下一字符
		}
		else		//处理普通操作符
		{
			tempChar = GetTopL(op);
			preOp = Precede(tempChar, expRead);
			if (expRead == ')')
			{
				tempChar = PopL(op);
				while (tempChar != '(')
				{
					PushL(postexp, tempChar);
					//PushL(postexp, '#');

					tempChar = PopL(op);
				}
			}
			else if (preOp == '>')
			{
				PushL(postexp, PopL(op));
				PushL(op, expRead);
				//PushL(postexp, '#');
			}
			else if (preOp == '<')
				PushL(op, expRead);
		}
	}

	while (op->next->data != '#')
	{
		tempChar = PopL(op);
		PushL(postexp, tempChar);
	}
}

int ary(int expn)
{
	int i;
	int sum = 1;
	for (i = 0; i < expn; i++)
	{
		sum *= 10;
	}
	return sum;
}

int getValue(stackL *assistStack)//求得属于同一数值的连续数符的值
{
	int value = 0;
	int ex = 0;
	char charValue;
	charValue = PopL(assistStack);
	while (charValue != '#')
	{
		value += (charValue - 48)*ary(ex);
		ex++;
		charValue = PopL(assistStack);
	}
	return value;
}

void pushBack(stackL *postexp, int valueBack)//将计算出来的int值化作字符,并从低位到高位压入主栈中
{
	int i = 0;
	char valueChar;
	if (valueBack == 0)
		PushL(postexp, '0');
	while (valueBack != 0)
	{
		valueChar= (valueBack % 10)+48;
		PushL(postexp, valueChar);
		valueBack = valueBack / 10;
	}
	PushL(postexp, '#');
}

int power(int value, int expn)
{
	int result = 1;
	for (int i = 0; i < expn; i++)
	{
		result *= value;
	}
	return result;
}
int partCalu(stackL *postexp,stackL *assistStack )//计算小段式的值,此时两个操作数分别在两个栈中,操作数在辅助栈里
{
	int value_1, value_2, value_3;
	char opera;
	PushL(assistStack, PopL(postexp));
	while (GetTopL(postexp) <= '9'&&GetTopL(postexp) >= '0')//使两个操作数和运算符都在辅助栈中,方便操作数的还原
	{
		PushL(assistStack, PopL(postexp));
	}

	value_1 = getValue(assistStack);
	value_2 = getValue(assistStack);
	opera = PopL(assistStack);

	switch (opera)
	{
	case '+':
		value_3 = value_1 + value_2;
		break;
	case '-':
		value_3 = value_1 - value_2;
		break;
	case '*':
		value_3 = value_1 * value_2;
		break;
	case '/':
		if (value_2 == 0)
		{
			cout << "error:除数为0" << endl;
			return 0;
		}
		else
		value_3 = value_1 / value_2;
		break;
	case'^':
		value_3 = power(value_1, value_2);
	default:
		break;
	}
	if (assistStack->next == NULL && postexp->next == NULL)
	{
		cout << value_2;
		return 0;
	}
	else if (assistStack->next == NULL && postexp->next->next == NULL)//结束条件
	{
		cout << value_3;
		return 0;
	}
	pushBack(postexp, value_3);//将部分求值结果重新压入主栈

	if (GetTopL(assistStack) <= '9'&&GetTopL(assistStack) >= '0')//再次满足部分求值条件
		partCalu(postexp, assistStack);
}
int caluValue(stackL *postexp)
{
	int control = 1;
	int value = 0;
	stackL *assistStack;
	char postRead,opera;
	assistStack = (stackL*)malloc(sizeof(stackL));
	InitStackL(assistStack);

	postRead = GetTopL(postexp);
	while (postexp->next != NULL)
	{
		/*主栈栈顶为#时进行是否部分求值检测,
		如果辅助栈顶为数符的话,则进行部分求值,求值后将值继续压入主栈,
		压入时注意低位先压入,这样就可以在连续求值时进行递归*/
		if (postRead == '#'&&assistStack->next!=NULL)
		{
			if (GetTopL(assistStack) <= '9'&&GetTopL(assistStack) >= '0')
			{
				control =partCalu(postexp, assistStack);
				if (control == 0)
					return 0;
			}
				
			else if(GetTopL(assistStack) > '9'|| GetTopL(assistStack) < '0')
				PushL(assistStack, PopL(postexp));
		}
		else if (postRead == 'a'||postRead == 's')
		{
			opera=PopL(postexp);
			if (GetTopL(postexp) != '#')
			{
				cout << "单目运算符运用错误,应放在数字后" << endl;
				exit(0);
			}
			else
			{
				PushL(assistStack,PopL(postexp));
				while (GetTopL(postexp) <= '9'&&GetTopL(postexp) >= '0')//将数符弹出主栈 并压入辅助栈中
				{
					PushL(assistStack, PopL(postexp));
				}
				if (opera == 'a')
					pushBack(postexp, getValue(assistStack) + 1);
				else if (opera == 's')
					pushBack(postexp, getValue(assistStack) - 1);
			}
		}
		else
			PushL(assistStack, PopL(postexp));
		postRead = GetTopL(postexp);
	}
}

int main()
{
	while (1)
	{
		string express;
		cout << "please enter the expression statement,and end with '#'" << endl;
		cin >> express;

		stackL *op, *postexp;
		op = (stackL*)malloc(sizeof(stackL));	// 操作符栈
		postexp = (stackL*)malloc(sizeof(stackL));	//后缀表达式栈

		tranPost(op, postexp, express);	//将输入的中缀表达式转化为后缀表达式
		cout << express << " = ";
		caluValue(postexp);	//计算后缀表达式的值
		cout << "\n\n";
		free(op);
		free(postexp);
	}
}


stack.h

#include<stdlib.h>
#include<iostream>

using namespace std;

typedef char Elemtype;

typedef struct LinkStack
{
	Elemtype data;
	struct LinkStack *next;
}stackL;

//初始化
void InitStackL(stackL *lst)
{
	lst->next = NULL;
}
//判断是否为空,为空则返回1
int StackLEmpty(stackL *lst)
{
	return (lst->next == NULL);
}

//压入
void PushL(stackL *lst, Elemtype x)
{
	stackL *p;
	p = (stackL*)malloc(sizeof(stackL));
	p->next = lst->next;
	p->data = x;
	lst->next = p;
}

//弹出
Elemtype PopL(stackL* lst)
{
	stackL *toFree;
	if (lst->next == NULL);
		//cout << "the stack is empty\n";
	else
	{
		Elemtype x;
		x = (lst->next)->data;
		toFree = lst->next;
		lst->next = (lst->next)->next;
		free(toFree);
		return x;
	}
	return 0;
}

//获取栈顶元素
Elemtype GetTopL(stackL* lst)
{
	if (lst->next == NULL);
		//cout << "the stack is empty\n";
	else
	{
		Elemtype x;
		x = lst->next->data;
		return x;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36907160/article/details/83212631