C++学习之(栈) 实践之(逆波兰公式)

栈(statck)这种数据结构在计算机中是相当出名的。栈中的数据是先进后出的(First In Last Out, FILO)。栈只有一个出口,允许新增元素(只能在栈顶上增加)、移出元素(只能移出栈顶元素)、取得栈顶元素等操作。在STL中,栈是以别的容器作为底部结构,再将接口改变,使之符合栈的特性就可以了。因此实现非常的方便。在STL中栈一共就5个常用操作函数(top()、push()、pop()、 size()、empty() ),很好记的。

C++学习之(栈) 实践之(逆波兰公式)_第1张图片

 
#include <iostream>
#include <vector>
#include <stack>
#include <list>
using namespace std;
int main()
{
	//定义栈 使用list作为容器
	stack<int,list<int>> a; 
	stack<int,vector<int>> b; 
	int i;
	//压入栈数据
	for(i = 0;i < 10;i++)
	{
		a.push(i);
		b.push(i);

	}
	//输出栈size的大小
	cout<<"a stack size : " << a.size()<<endl;
	//取栈项数据并将数据弹出栈  
	cout<<"a 中的数据:";
	while(!a.empty())
	{
	   cout<<a.top()<<" ";
	   //栈顶元素弹出栈
	   a.pop();
	}
	cout<<endl;
	cout<<"b 中的数据:";
	while(!b.empty())
	{
	   cout<<b.top()<<" ";
	   //栈顶元素弹出栈
	   b.pop();
	}
	system("pause");
    return 0;
}


栈的实践使用:逆波兰公式

表达式一般由操作数(Operand)、运算符(Operator)组成,例如算术表达式中,通常把运算符放在两个操作数的中间,
这称为中缀表达式(Infix Expression),如A+B。
波兰数学家Jan Lukasiewicz提出了另一种数学表示法,它有两种表示形式:
把运算符写在操作数之前,称为波兰表达式(Polish Expression)或前缀表达式(Prefix Expression),如+AB;
把运算符写在操作数之后,称为逆波兰表达式(Reverse Polish Expression)或后缀表达式(Suffix Expression),如AB+;
其中,逆波兰表达式在编译技术中有着普遍的应用。
 
算法:
一、 将中缀表达式转换成后缀表达式算法:
1、从左至右扫描一中缀表达式。
2、若读取的是操作数,则判断该操作数的类型,并将该操作数存入操作数堆栈
3、若读取的是运算符
  (1) 该运算符为左括号"(",则直接存入运算符堆栈。
  (2) 该运算符为右括号")",则输出运算符堆栈中的运算符到操作数堆栈,直到遇到左括号为止。
  (3) 该运算符为非括号运算符:
      (a) 若运算符堆栈栈顶的运算符为括号,则直接存入运算符堆栈。
      (b) 若比运算符堆栈栈顶的运算符优先级高或相等,则直接存入运算符堆栈。
      (c) 若比运算符堆栈栈顶的运算符优先级低,则输出栈顶运算符到操作数堆栈,并将当前运算符压入运算符堆栈。
4、当表达式读取完成后运算符堆栈中尚有运算符时,则依序取出运算符到操作数堆栈,直到运算符堆栈为空。
 
二、逆波兰表达式求值算法:

      对后缀表达式求值比直接对中缀表达式求值简单。在后缀表达式中,不需要括号,而且操作符的优先级也不再起作用了。您可以用如下算法对后缀表达式求值:

  1. 初始化一个空堆栈
  2. 从左到右读入后缀表达式
  3. 如果字符是一个操作数,把它压入堆栈。
  4. 如果字符是个操作符,弹出两个操作数,执行恰当操作,然后把结果压入堆栈。如果您不能够弹出两个操作数,后缀表达式的语法就不正确。
  5. 到后缀表达式末尾,从堆栈中弹出结果。若后缀表达式格式正确,那么堆栈应该为空。
<pre name="code" class="cpp">#include <iostream>
#include <stack>
#include <list>
using namespace std;
//声明函数
bool isOperand(char c);
bool isOpertor(char c);
bool ComaprePriority(char op1,char op2);
int getPriorityValue(char c);
int Operate(char op, int operand1, int operand2);

//判断是否为数字
bool isOperand(char c)
{
	  return ( c == '0' || c == '1' || c == '2' || c == '3' || c == '4' ||

                               c == '5' || c == '6' || c == '7' || c == '8' || c == '9' );
}
//判断是否为运算符
bool isOpertor(char c)
{
	   return ( c == '+' || c == '-' || c == '*' || c == '/' ||

                               c == '(' || c == ')' );
}
//判断运算符优先级大小 op1优先级高于或者等于op2返回true
bool ComaprePriority(char op1,char op2)
{
	return (getPriorityValue(op1) >= getPriorityValue(op2)) ;
}

//获取运算符优先级
int getPriorityValue(char c)
{
	int prioityValue;
	switch(c)
	{
	case '+ ':
		prioityValue = 1;
		break;
	case '-':
		prioityValue = 1;
		break;
	case '*':
		prioityValue = 2;
		break;
	case '/':
		prioityValue = 2;
		break;
	default:
		prioityValue = 0;
	}
	return prioityValue;
}

int Operate(char op, int operand1, int operand2)

{
      switch(op)
      {
      case '+':
            return operand1 + operand2;
      case '-':
            return operand1 - operand2;
      case '*':
            return operand1 * operand2;
      case '/':
            return operand1 / operand2;
      default:
            return -1;
      }
}


int main()
{
	//定义栈 使用list作为容器
	stack<char> operand; 
	stack<char> opertor; 
	char str[20] = "(2+4)*4+1";
	//压入栈数据
	int length = strlen(str);
	for(int i = 0;i < length;i++)
	{
		
		char c = str[i];
		cout<<c<<" ";
		//判断是否为操作数
		if (isOperand(c))
		{
			operand.push(c);
		}
		else
		{
			//为运算符
			//若运算符为"("直接存入到运算符栈中
			if( c == '(')
			{
				opertor.push(c);
			}
			else if(c == ')')
			{
				//该运算符为右括号")",则输出运算符堆栈中的运算符到操作数堆栈,直到遇到左括号为止。
				while(opertor.top() != '(')
				{
					char op = opertor.top();
					opertor.pop();
					operand.push(op);	
				}
				//将'('出栈
				opertor.pop();
			}
			else
			{ // 该运算符为非括号运算符:
			  // (a) 若运算符堆栈栈顶的运算符为括号,则直接存入运算符堆栈。
			  //考虑栈顶为空的情况
			  if(opertor.empty())
			  {
				opertor.push(c);
				continue;
			  }
			  if(opertor.top() == '(')
			  {
				opertor.push(c);
			  }
			  else
			  {
				  //(b) 若比运算符堆栈栈顶的运算符优先级高或相等,则直接存入运算符堆栈。
				  if(ComaprePriority(c,opertor.top()))
				  {
					opertor.push(c);
				  }
				  else
				  {
					// (c) 若比运算符堆栈栈顶的运算符优先级低,则输出栈顶运算符到操作数堆栈,并将当前运算符压入运算符堆栈。
					char op = opertor.top();
					operand.push(op);
					opertor.pop();
					opertor.push(c);
				  }// if(ComaprePriority(c,opertor.top()))
			  }//end  if(opertor.top() == '(')	
			}//end if( c == '(')
		}//end 	if (isOperand(c))
	}//end for
	//4、当表达式读取完成后运算符堆栈中尚有运算符时,则依序取出运算符到操作数堆栈,直到运算符堆栈为空。
	while(!opertor.empty())
	{
		char op = opertor.top();
		operand.push(op);
		opertor.pop();
	}
	//cout<<endl<<"转换后的逆波兰表达式:";
	//输出转换后的逆波兰表达式
	//while(!operand.empty())
	//{
	//	cout<<operand.top()<<" ";
	//	operand.pop();
	//}

	//计算逆波兰表达式
	stack<char> stackOper;
	stack<int> stackresult;//计算使用栈
	//上面计算后的栈是反着的 把它倒转过来计算
	while(!operand.empty())
	{
		//cout<<operand.top()<<" ";
		char op = operand.top();
		stackOper.push(op);
		operand.pop();
	}
	//计算逆波兰表达式
	while(!stackOper.empty())
	{
		char op = stackOper.top();
		//如果字符是一个操作数,把它压入堆栈。 
		if (isOperand(op))
		{
			int num ;
			num = atoi(&op);
			stackresult.push(num);
		}
		else
		{
			//如果字符是个操作符,弹出两个操作数,执行恰当操作,然后把结果压入堆栈。如果您不能够弹出两个操作数,后缀表达式的语法就不正确。
			int number1 = stackresult.top();
			stackresult.pop();
			int number2 = stackresult.top();
			stackresult.pop();
			//弹出两个操作符执行运算
			int result =  Operate(op,number1,number2);
			stackresult.push(result);
		}
		stackOper.pop();
	}
	//输出计算结果
	cout<<" = " <<  stackresult.top()<<endl;
	system("pause");
    return 0;
}
 
 

 

 

 

 

你可能感兴趣的:(C++,栈,逆波兰表达式)