数据结构算法之通过栈实现四则运算

栈是我目前学到的感觉最简单的一种数据结构,它就是一个有限制性的链表,进栈的一段我们称之为top,出栈的一头我们称之为栈顶base,如下图

在这里插入图片描述
它的基本结构形式是的一个栈顶指针,还有一个栈底指。
typedef int Elemdate;

typedef struct _Stack{
Elemdate *top;
Elemdate *base;
}Stack;
//这就是栈的一个基本构造形式

具体实现略过。我们现在要利用栈实现计算一个带括号的四则运算。但是它栈的应用斯泽夫元素是我感觉到比较难以理解的地方,下面我们来看这些。

运算符是这样的: 15+73(2+1) 我们要计算得的数字是这样的,
利用栈的中缀法则我们需要创建两个栈 一个栈存入操作数 另一个栈存入操作符号
在这里插入图片描述
它的运算顺序是这样的 15+73(2+1)
首先我们让数字15进栈,但是我们这里输入的是字符串那么我们如何让

//栈的四则运算,支持有括号的形式
//5+7*3*(2+1)
#include<stdio.h>
#include<Windows.h>
#include<iostream>
#include<string>


using namespace std;


typedef  int Elemdate;
#define MAX_SIZE 10

typedef struct _Stack {
	Elemdate* base;
	Elemdate* top;

}Stack;

//栈的初始化
bool initStack(Stack& stack) {

	stack.base = new int[MAX_SIZE];

	if (!stack.base) {

		printf("栈初始化失败!\n");
		return false;

	}

	stack.top = stack.base;
	return true;

}

//获取栈顶元素
Elemdate* getTop(Stack& stack) {
	if (stack.top != stack.base) {
		return stack.top - 1;
	}
	else {
		return NULL;
	}

}
//入栈
bool PushStack(Stack& stack, int date) {

	if (stack.top - stack.base == MAX_SIZE) {

		printf("栈空间已满,入栈失败!\n");
		return false;
	}

	*(stack.top++) = date;
	return true;

}

//出栈
bool PopStack(Stack& stack, int& date) {
	if (stack.base == stack.top) {
		printf("无元素可出栈!\n");
		return false;
	}


	date = *(--stack.top);
	return true;

}

//判断栈是否为空
bool isEmpty(Stack& stack) {
	if (stack.base == stack.top) {
		return true;

	}

	return false;
}
//判断栈是否已满
bool isFully(Stack& stack) {

	if (stack.top - stack.base == MAX_SIZE) {

		return true;
	}
	return false;
}

//销毁栈
void destoyedStack(Stack& stack) {

	if (!&stack) return;

	delete[MAX_SIZE] stack.base;

	stack.base = stack.top = NULL;


}

//获取以元素个数
int getElemdateCount(Stack& stack) {


	return (stack.top - stack.base);
}

//四则运算机算
int operatored(int ldate, int opt, int rdate) {

	int result = 0;

	cout << "left:" << ldate << "right" << rdate << "opt" << (char)opt << endl;


	switch (opt) {

	case '+':
		result = ldate + rdate;
		break;
	case '-':
		result = ldate - rdate;
		break;
	case '*':
		result = ldate * rdate;
		break;
	case '/':
		result = ldate / rdate;
		break;
	default:
		break;

	}
	//cout << "reslut:" << result << endl;
	return result;

}

//判断栈顶元素的优先级和当前获取的运算符优先级
bool isLarger(const int& input, const int& top) {//top代表的是栈顶符号元素,input代表的是当前符号元素

	/*if((rhs=='+'|rhs=='-')&&(lhs=='*'||lhs=='/')){
	return true;
	}else
	{
	return false;
	}*/
	//这里

	//如果当前元素比栈顶元素大直接入栈,否则要计算在入栈
	//8/大于
	if ((input == '*' || input == '/') && (top == '-' || top == '+' || top == '('))
		return true;
	else
		return false;
	if ((input == '+' || input == '-') && top != '(')
		return true;
	else
		return false;

	if ((input == '('))	//直接入栈 
		return true;



}
int caculate(string input) {


	/*
	入栈顺序
	5先进操作数栈
	+直接进操作符栈
	7直接进操作数栈
	*直接进操作符栈
	3直接进操作数栈
	遇到*先不进栈
	先计算7*3
	注意从操作数栈 出栈元素 3 7  3先出放在右边 7后出放在左边 中间是*操作符,那么从程序中怎么判断呢?
	然后得到运算吧结果 21 将 21 入操作数字栈 现在操作数栈  5 21  操作符栈 +
	*入操作符栈
	遇到(  直接入操作符栈  2直接入操作数栈 +直接入操作符栈 然后在是1直接入操作数栈
	此时操作数栈为  5 21 2 1
	操作符栈为      + * ( +
	先执行括号里面的
	出栈2 1 和+,1在右侧  2 在左侧 + 计算 2+1 = 3,出栈标识符是,遇到了'('那么这个符号栈就不出元素了 3入栈  (出栈
	5 21 3    + *
	出栈   21 3 *    21*3=63
	5 63   +
	出栈 5 63 +
	计算  5 + 63 = 68
	然后  入栈返回栈顶元素

	*/
	bool shiftis0 = false;
	int tmpDATE;
	int tmpOPT;
	Stack stack_date;	//操作数
	Stack stack_opt;

	//PushStack(stack_opt,'#');

	initStack(stack_date);
	initStack(stack_opt);
	int ldate = 0;
	int result = 0;
	//当然里面最多只可能有两个操作符
	int TemOpt;
	int TmpLdate = 0, TmpRdate = 0;
	//15+7*3*(2+1)

	for (int i = 0; i < input.length(); i++) {

		//if(isspace(input[i])) continue;

		if (getTop(stack_date))	tmpDATE = *getTop(stack_date);
		if (getTop(stack_opt)) tmpOPT = *getTop(stack_opt);

		if (isdigit(input[i])) {
			//如果是数字并且为空,直接入栈
		//	if(isEmpty(stack_date)){
				//ldate *=10;
			ldate = input[i] - '0';

			while (isdigit(input[i + 1])) {
				//判断接下来的i+1是数字还是字符,如果是数字直接推进去,否则
				i++;
				ldate *= 10;
				ldate = ldate + input[i] - '0';

			}
			PushStack(stack_date, ldate);//别急入栈,这里面我想要的是15入栈而不1入栈,怎么办
			cout << "操作数" << ldate << "入栈" << endl;
			ldate = 0;
			continue;			//	}

		}


		if (input[i] == '+' || input[i] == '-' || input[i] == '*' || input[i] == '/' || input[i] == '(' || input[i] == ')') {
			//这些运算符的时候
			if (input[i] == '(') {
				PushStack(stack_opt, input[i]);
				cout << "操作符" << (char)input[i] << "入栈" << endl;
				shiftis0 = true;
				continue;
			}


			if (isEmpty(stack_opt) && input[i]) {
				cout << "运算符" << char(input[i]) << "入栈" << endl;
				PushStack(stack_opt, input[i]);

			}
			else {
				//运算符栈不为空的情况下//
				int dmCount=0;//乘号和除号的个数
				int kcount = 0;
				

				//首先判断这个符号 ')',遇到它就要一直出栈到栈顶元素为'('的时候就停止并且还要计算值压栈
				if (input[i] == ')'&& kcount==0) {
					kcount++;

					char char_opt[30] ; //存储这个符号
					int int_opt[30];

					//反转数组
					char pchar_opt[30];
					int pint_opt[30];
					int i_count = 0;

					

					while (*getTop(stack_opt)!=NULL &&*getTop(stack_opt) != '(') {

					
						PopStack(stack_date, TmpLdate);
						int_opt[i_count] = TmpLdate;

						PopStack(stack_opt, TemOpt);
						if (TemOpt == '/' || TemOpt=='*') dmCount++;

						char_opt[i_count] = TemOpt;

						i_count++;

						//乘号和除号的个数


						//只要是不等于
						//
						/*PopStack(stack_opt, TemOpt);
						cout << "操作符:" << (char)TemOpt << "出栈" << endl;
						PopStack(stack_date, TmpRdate);


						cout << "操作数:" << TmpRdate << "出栈" << endl;
						PopStack(stack_date, TmpLdate);
						
						cout << "操作数:" << TmpLdate << "出栈" << endl;

						result = operatored(TmpLdate, TemOpt, TmpRdate);

						PushStack(stack_date, result);	//数据放进去

						cout << "操作数:" << result << "入栈" << endl;*/

						/*
						
						思想先算 乘除 后算加减
						数字搞一个数组
						符号搞一个数组
						//例如 3+5-2*7-8  
						数组中进入的为  3 5 2 7 8
						符号数字进入的  + - * -


						*/
					}
					static int Final_Ruslt=1;

					PopStack(stack_date, TmpLdate);
					Final_Ruslt = TmpLdate;
					//if (getTop(stack_date) == NULL) return TmpLdate;

					int_opt[i_count] = TmpLdate;//这里要加一

					int dgt_count = i_count + 1;

					for (int x1 = 0; x1 < i_count; x1++) {
						//倒置符号数组
						pchar_opt[x1] = char_opt[i_count - 1 - x1];
					}
					
					for (int x2 = 0; x2 <= i_count; x2++) {
					
						pint_opt[x2] = int_opt[i_count - x2];
					}

					for (int i = 0; i < i_count; i++) {
						char tmp_char;
						int tmp_L, tmp_R;
						int tmp_result;
						//定位特殊符号 *和÷的个数
						if (dmCount > 0) {
						
							
							//扫描找到它
						
							//取出符号位,和数字位置
							
							if (pchar_opt[i] == '*' || pchar_opt[i] == '/') {
								
								tmp_char = pchar_opt[i];
								tmp_L = pint_opt[i];
								tmp_R = pint_opt[i + 1];

								tmp_result = operatored(tmp_L, tmp_char, tmp_R);
								Final_Ruslt = tmp_result;	//这里给Final_Reult赋初值的目的是

								pint_opt[i] = tmp_result;//把计算的结果放入数组中

								//数组中进入的位 3 5 2 7 8 
								//符号数字进入的 + - * -
								//3+5-14-8
								//定位到符号位2 i_count为三
								//移动的个数为1
								//对符号处理
								for (int j = i; j < i_count; j++) {
									
									pchar_opt[j] = pchar_opt[j + 1];
								
								}
								//对数字处理

								for (int m = i + 1; m < dgt_count; m++) {
									
									pint_opt[m] = pint_opt[m + 1];
								}

								dmCount--;//符号位自减
								
								i_count--;	//数组中的符号个数自减
								dgt_count--;//数组中的数字自减去
								i = -1;//从新开始

								continue;
							}
						
						}
					//否则没有符号位的话那么就只有加减我们还是一样的
						if (dmCount == 0) {
						
							//3+5-14-8
							 Final_Ruslt = pint_opt[i];
						
							Final_Ruslt = operatored(Final_Ruslt, pchar_opt[i], pint_opt[i + 1]);
							cout << "括号呈递的数:" << Final_Ruslt << endl;
							}


						}




					PopStack(stack_opt, TemOpt);//把'('推出
					cout << "操作符:" << (char)TemOpt << "出栈" << endl;

					
					PushStack(stack_date, Final_Ruslt);

					shiftis0 = false;
					continue;

				}

				if (shiftis0) {
					PushStack(stack_opt, input[i]);
					cout << "操作符:" << (char)input[i] << "入栈" << endl;
					continue;
				}

				if (isLarger(input[i], *getTop(stack_opt))) {
					//如果当前运算符大于栈顶直接入栈
					PushStack(stack_opt, input[i]);
					cout << "操作符:" << (char)input[i] << "入栈" << endl;
				}
				else {
					//否则要进行计算
					while (getTop(stack_opt) != NULL && ((isLarger(input[i], *getTop(stack_opt))) == false)) {

						//当然里面最多只可能有两个操作符
							//(15+7)*3*2+1

						//这里推出的只是一个数字
						PopStack(stack_opt, TemOpt);
						cout << "操作符:" << (char)TemOpt << "出栈" << endl;
						PopStack(stack_date, TmpRdate);
						cout << "操作数:" << TmpRdate << "出栈" << endl;
						PopStack(stack_date, TmpLdate);
						cout << "操作数:" << TmpLdate << "出栈" << endl;

						result = operatored(TmpLdate, TemOpt, TmpRdate);

						PushStack(stack_date, result);//数据放进去
						cout << "操作数:" << result << "入栈" << endl;
					}
					PushStack(stack_opt, input[i]);
					cout << "操作符:" << (char)TemOpt << "出栈" << endl;
				}


			}

		}

	}
	//符号进去完了,就开始计算了15+21*3
	//只要有符号就一直运算有几个运算号就运算几次
	int n = getElemdateCount(stack_opt);
	//if (n == 1) return *getTop(stack_date);

	for (int i = 0; i < n; i++) {

		PopStack(stack_opt, TemOpt);
		PopStack(stack_date, TmpRdate);
		PopStack(stack_date, TmpLdate);

		result = operatored(TmpLdate, TemOpt, TmpRdate);
		PushStack(stack_date, result);
	}

	return *getTop(stack_date);
}


int main(void) {

//
	
	string s = "8*6*(9-6*45)*32+1";
	

	int result = caculate(s);

	cout << "result:" << result << endl;

	system("pause");
	return 0;
}

运行效果在这里插入图片描述

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值