中缀表达式转后缀表达式

一、基本概念

中缀表达式:运算符都在运算数之间的表达式,也就是我们日常见到的表达式,包含括号。例如:(1+2)*5

后缀表达式:别称逆波兰式,指的是严格从左向右按照运算符出现的顺序进行计算,不包含括号,运算符都放在运算对象的后面的。例如:1 2 + 5 * 就是一个后缀表达式,是由前面中缀表达式的例子转换的。

为什么要转换成后缀表达式?中缀表达式不行吗?

那是因为对于一个中缀表达式 5+8/2 ,我们人可以轻易知道各运算的次序得到答案 9 ,可是计算机不能,计算机很笨,所以需要转换成后缀表达式 5 8 2 / +,这样计算机就能在不考虑各符号优先级的情况下,也得出答案 9(计算机从左向右遍历,将5、8、2入栈,遇到 / ,将8、2出栈,将 8/2 的结果入栈,此时栈中有 5 4 ,遇到 +,将5、4出栈,将 5+4 的结果入栈,遍历完了,栈中有 9,这就是答案。)

 二、中缀表达式转后缀表达式----栈的应用

思路:先从左向右遍历整个中缀表达式

1、如果是运算数:直接输出到后缀表达式

2、遇到左括号 ( :压入栈中,把左括号当做优先级最低的符号

3、遇到右括号 ) :意味着括号中的运算结束了,将运算符一个一个弹出栈顶并且输出到后缀表达式,直到遇到左括号,但是左括号不加入到后缀表达式

4、对于运算符 + - * /:

        1.如果优先级大于栈顶的运算符或者栈为空时,入栈

        2.否则,即优先级小于等于栈顶的运算符,就将栈顶依次弹出到后缀表达式中去,直到满足入栈条件。

( 此时是优先级最低的符号

遍历完中缀表达式后,可能栈中还存有运算符,依次弹出直至栈空。

转换过程分析(以(3+5)*3-2/1为样例,结果是3 5 + 3 * 2 1 / -)

1.遍历到(,入栈
后缀表达式为:
栈中元素:(
2.遍历到3,输出到后缀表达式
后缀表达式为:3
栈中元素:(
3.遍历到+(优先级1),大于栈顶元素(的优先级,入栈
后缀表达式为:3
栈中元素:(+
4.遍历到5,输出到后缀表达式
后缀表达式为:3 5
栈中元素:(+
5.遍历到),一直出栈输出到后缀表达式,直到遇到(,但是(不加入后缀表达式
后缀表达式为:3 5 +
栈中元素:
6.遍历到*,栈为空,入栈
后缀表达式为:3 5 +
栈中元素:*
7.遍历到3,输出到后缀表达式
后缀表达式为:3 5 + 3
栈中元素:*
8.遍历到-,小于等于*的优先级,*出栈输出到后缀表达式,-入栈
后缀表达式为:3 5 + 3 *
栈中元素:-
9.遍历到2,输出到后缀表达式
后缀表达式为:3 5 + 3 * 2
栈中元素:-
10.遍历到/,/的优先级大于-,入栈
后缀表达式为:3 5 + 3 * 2
栈中元素:-/
11.遍历到1,输出到后缀表达式
后缀表达式为:3 5 + 3 * 2 1
栈中元素:-/
12.遍历完了,可是栈未空,出栈直至栈空
后缀表达式为:3 5 + 3 * 2 1 / -
栈中元素: 

至此结束 。

三、代码

转换代码:

int priority(char ch) //返回优先级-优先级越高值越大
{
	if (ch == '(')
	{
		return 0;
	}

	else if (ch == '+' || ch == '-')
	{
		return 1;
	}
	else //    * /
	{
		return 2;
	}
}

void trans(string arr1, string &arr2)
{

	Stack stack;
	initStack(stack);

	DateElem e = ' '; //用于传出栈中元素

	for (int i = 0; i < arr1.size(); i++) //每次arr2加入元素后,都加一个空格以分割
	{
		if (arr1[i] == ' ') //跳过空格
		{
			continue;
		}

		if(arr1[i] >= '0' && arr1[i] <= '9') //情况1
		{
			while (arr1[i] >= '0' && arr1[i] <= '9')
			{
				arr2.push_back(arr1[i]);
				i++;
			}
			arr2.push_back(' ');
			i--; //因为当不是数字时,i也++了,i等下循环中还要++,所以得--
		}

		else if (arr1[i] == '(' ) //情况2
		{
			pushStack(stack, arr1[i]);
		}


		else if (arr1[i] == ')') //情况3
		{
			while (!IsEmpty(stack) && getTop(stack)!='(')
			{
				popStack(stack, e);
				arr2.push_back(e);
				arr2.push_back(' ');
			}
			if(getTop(stack) == '(')
				popStack(stack,e); //将 '(' 弹出栈
		}
		else //情况4
		{
			
			while (!IsEmpty(stack) && priority(getTop(stack) ) >=priority( arr1[i] )) //栈不为空 并且 栈顶元素优先级大于等于遍历的字符
			{
				popStack(stack, e);
				arr2.push_back(e);
				arr2.push_back(' ');
			}
			pushStack(stack, arr1[i]); //循环结束,就满足入栈条件,栈为空 或者 优先级小于栈顶元素
		}
	}

	while (!IsEmpty(stack))  //输出栈中剩余的元素
	{
		popStack(stack, e);
		arr2.push_back(e);
		arr2.push_back(' ');
	}

	return;

}

全部代码:

#define _CRT_SECURE_NO_WARNINGS 1

#include 
#include 

using namespace std;

//栈的数据结构定义
#define MAX_SIZE 120

typedef char DateElem;
typedef struct _Stack
{
	DateElem* top;
	DateElem* base;
}Stack;

//初始化栈
bool initStack(Stack& s)
{
	s.base = new DateElem[MAX_SIZE];
	if (!s.base) return false; //空间分配失败

	s.top = s.base; //空栈
	return true;
}

//入栈
bool pushStack(Stack& s, DateElem e)
{
	if (!s.base || (s.top - s.base) >= MAX_SIZE) return false; //栈没建立 或者 栈满了

	*(s.top++) = e;
	return true;
}


//出栈
bool popStack(Stack& s, DateElem& e)
{
	if (!s.base || s.base == s.top) return false;

	e = *(--s.top); //先将栈顶元素赋值给e,栈顶指针再移动,因为栈顶指针都是指向栈顶元素的后一个位置
	return true;
}

//获取栈顶元素
DateElem getTop(Stack& s)
{
	if (s.top > s.base) //栈不为空
	{
		return *(s.top - 1);
	}
	else
	{
		cout << "栈为空" << endl;
		return 1;
	}
}

//判断栈是否为空
bool IsEmpty(Stack& s)
{
	if (s.base == s.top)
	{
		return true;
	}
	else
	{
		return false;
	}

}

//获取栈中元素的个数
int getLength(Stack& s)
{
	return (int)(s.top - s.base);
}

//销毁栈
void destoryStack(Stack& s)
{
	//与初始化栈一一对应
	if (s.base != NULL) //有效
	{
		delete s.base;
		s.base = s.top = NULL;
	}

}

int priority(char ch) //返回优先级-优先级越高值越大
{
	if (ch == '(')
	{
		return 0;
	}

	else if (ch == '+' || ch == '-')
	{
		return 1;
	}
	else //    * /
	{
		return 2;
	}
}

void trans(string arr1, string &arr2)
{

	Stack stack;
	initStack(stack);

	DateElem e = ' '; //用于传出栈中元素

	for (int i = 0; i < arr1.size(); i++) //每次arr2加入元素后,都加一个空格以分割
	{
		if (arr1[i] == ' ') //跳过空格
		{
			continue;
		}

		if(arr1[i] >= '0' && arr1[i] <= '9') //情况1
		{
			while (arr1[i] >= '0' && arr1[i] <= '9')
			{
				arr2.push_back(arr1[i]);
				i++;
			}
			arr2.push_back(' ');
			i--; //因为当不是数字时,i也++了,i等下循环中还要++,所以得--
		}

		else if (arr1[i] == '(' ) //情况2
		{
			pushStack(stack, arr1[i]);
		}


		else if (arr1[i] == ')') //情况3
		{
			while (!IsEmpty(stack) && getTop(stack)!='(')
			{
				popStack(stack, e);
				arr2.push_back(e);
				arr2.push_back(' ');
			}
			if(getTop(stack) == '(')
				popStack(stack,e); //将 '(' 弹出栈
		}
		else //情况4
		{
			
			while (!IsEmpty(stack) && priority(getTop(stack) ) >=priority( arr1[i] )) //栈不为空 并且 栈顶元素优先级大于等于遍历的字符
			{
				popStack(stack, e);
				arr2.push_back(e);
				arr2.push_back(' ');
			}
			pushStack(stack, arr1[i]); //循环结束,就满足入栈条件,栈为空 或者 优先级小于栈顶元素
		}
	}

	while (!IsEmpty(stack))  //输出栈中剩余的元素
	{
		popStack(stack, e);
		arr2.push_back(e);
		arr2.push_back(' ');
	}

	return;

}
int main(void)
{
	Stack stack;
	initStack(stack);


	string arr1 = "";
	string arr2= "";


	cout << "请输入中缀表达式:"; //((1+2)*3)-(6-5)
	getline(cin, arr1);

	trans(arr1, arr2);

	cout << "转为后缀表达式为:"; //1 2 + 3 * 6 5 - -
	cout << arr2 << endl;
	

	return 0;
}

其中包括了栈的代码,你也可以使用库中的栈。

你可能感兴趣的:(数据结构,数据结构,c++,算法)