数据结构学习笔记2——用栈计算后缀(postfix)表达的完整代码

实现《数据结构与算法分析 C++描述》3.6.3节的“后缀表达式”算法。

后缀表达式是类似于这样的表达式:6 5 2 3 + 8 * + 3 + *

求值过程为:当遇到一个数字时就将其压入栈中,在遇到一个操作符时,该操作符就作用于从该栈弹出的两个数字上,再将所得结果压入栈中。

为实现这一算法,需要用到上一节实现的栈,当然,为了方便使用,我们给上一节的栈增加了一个成员函数size()用于返回栈的大小

文件结构如下:

数据结构学习笔记2——用栈计算后缀(postfix)表达的完整代码_第1张图片

SeqStack_VT开头的文件是为了实现栈,都是上一节已经介绍过的.postfix中放的是后缀表达式运算算法。main.cpp中是主函数,测试算法是否能正常运行。


完整代码如下:

SeqStack_VT.h:模板的定义体

/********************************************************/
// 用vector和模板实现顺序栈(Sequence Stack)的数据定义
// 可以不用限制数据的最大个数和数据类型
/********************************************************/
#pragma once
#include "Public.h"

//定义顺序栈类,数据用vector存储,VT is short for Vector_Template
template
class Stack_VT
{
public:
	Stack_VT() :top_index(-1) {}        //默认构造函数
	void push(dataType const& elem);	//压入新成员,放在栈顶
	void pop();							//删除栈顶成员
	dataType top();						//返回栈顶成员
	void clear();						//清空栈
	bool isEmpty();						//判断栈是否为空
	void print(ostream& out);			//打印所有栈成员
	size_t size();                      //返回栈的大小(现存的元素个数)

private:
	vector data;				//用于存储数据的数组
	int      top_index;					//栈顶所在的数组下标		
};

SeqStack_VT_Def.h:模板的成员函数实现

/********************************************************/
// 用Vector和模板实现顺序栈(Sequence Stac)类Stack_VT的成员函数定义
// 模板版本,存储任意类型和任意长度数据
/********************************************************/
#pragma once
#include "SeqStack_VT.h"

//压入数据
template 
void Stack_VT::push(dataType const& elem)
{
	// vector的back就是栈的top
	data.push_back(elem);
	top_index++;
}

//弹出数据
template 
void Stack_VT::pop()
{
	if (!isEmpty())
	{
		data.pop_back();
		top_index--;
	}
}

//获取栈顶成员
template 
dataType Stack_VT::top()
{
	if (!isEmpty())
	{
		return data[top_index];
	}
	else
	{
		//错误应该如何处理??
		cout << "访问空栈的成员" << endl;
		return data[-1];		
	}
}

//清空栈
template 
void Stack_VT::clear()
{
	top_index = -1;
}

//判断栈是否为空
template 
bool Stack_VT::isEmpty()
{
	if (top_index >= 0)
	{
		return false;
	}
	else
	{
		return true;
	}
}

//返回栈的大小
template 
size_t Stack_VT::size()
{
	return top_index + 1;
}

//打印所有栈成员
template 
void Stack_VT::print(ostream& out)
{
	if (isEmpty())
	{
		out << "The stack is empty!" << endl;
	}
	else
	{
		for (size_t index = 0; index != top_index + 1; index++)
		{
			out << data[index] << endl;
		}
	}
}

postfix.h:后缀算法头文件

/********************************************************/
// 《数据结构与算法分析》3.6.3节 后缀记法的实现
/********************************************************/
#pragma once
#include "SeqStack_VT_Def.h"

double postfix_cal(string const& str);

postfix.cpp:后缀算法实现

/********************************************************/
// 《数据结构与算法分析》3.6.3节 后缀记法的实现
/********************************************************/
#include "SeqStack_VT_Def.h"

/********************************************************/
// 全局变量定义
/********************************************************/
//只支持四则运算
static const char Operator[4] = {'+','-','*','/'};
static const char blank[4] = {'\n','\t','\40','\r' };
vector vBlank(blank, blank + 4);
vector vOperator(Operator, Operator + 4);
/********************************************************/
// 函数声明
/********************************************************/
int check_string(string const& str);
int str2vector(string const& str, vector & sVector);
int process(vector & sVector,double &result);
int cal(Stack_VT &stack_str, string const &oper, double &result);

double postfix_cal(string const& str)
{
	int iErrorCode = 0;
	double result = 0.0;
	vector sVector;

	cout << str << endl;
	// 1,检查输入的字符串中是否有非法字符
	iErrorCode = check_string(str);

	// 2,将字符串按空白字符分隔,存进vector中
	if (0 == iErrorCode)
	{		
		iErrorCode = str2vector(str, sVector);
	}

	// 3,计算
	if (0 == iErrorCode)
	{
		iErrorCode = process(sVector,result);
	}

	// 4,返回结果
	if (0 == iErrorCode)
	{
		return result;
	}
	else
	{
		cout << "ERROR! iErrorCode = " << iErrorCode<< endl;
		return 0;
	}
}

//输入的字符串中只能含有0~9的数字、小数点、运算符和空白字符
int check_string(string const& str)
{
	bool bExist = false;	
	vector accept_char(Operator[0],Operator[3]);
	accept_char.push_back('.');
	accept_char.insert(accept_char.end(), blank[0], blank[3]);

	for (string::const_iterator iter = str.cbegin(); iter != str.cend(); iter++)
	{
		if (*iter < '0' && *iter > '9')
		{
			//没找到时,find返回第二个实参
			//字符既不在0到9之间,又不是其他的可能字符,报错
			if (accept_char.cend() == find(accept_char.cbegin(), accept_char.cend(), *iter))
			{
				cout << "The error input!" << endl;
				return 1;
			}
		}
	}

	//能安全走到这里就说明没有非法字符
	return 0;
}

int str2vector(string const& str, vector & sVector)
{
	string cur_str;//当前的字符串

	for (string::const_iterator iter = str.cbegin();
		 iter != str.cend();
		 iter++)
	{
		//输入的非空白字符
		if (vBlank.cend() == find(vBlank.cbegin(),vBlank.cend(),*iter))
		{
			cur_str.push_back(*iter);

			//到最后一个字符
			if (str.cend() == (iter + 1))
			{
				sVector.push_back(cur_str);
				
			}
			else
			{
				//本字符是运算符,或者,如果下一个字符是运算符号
				if ((vOperator.cend() != find(vOperator.cbegin(), vOperator.cend(), *iter) )||
					(vOperator.cend() != find(vOperator.cbegin(), vOperator.cend(), *(iter + 1))))
				{
					sVector.push_back(cur_str);
					cur_str.clear();
				}
			}			
		}
		else
		{
			//防止第一个字符就是空白字符,或者连续出现的空白字符
			//将空字符串push进stack会怎么样?
			if (!cur_str.empty())
			{
				sVector.push_back(cur_str);
				cur_str.clear();
			}
		}		
	}

	//如果结果里的第一个字符就是运算符,报错
	char oper = (*sVector.begin())[0];
	if (vOperator.cend() != find(vOperator.cbegin(), vOperator.cend(), oper))
	{
		cout << "第一个字符就是运算符,Error!" << endl;
		return 2;
	}

	//如果结果里的最后一个字符不是运算符,报错
	
	char oper_last = sVector[sVector.size() - 1][0];
	if (vOperator.cend() == find(vOperator.cbegin(), vOperator.cend(), oper_last))
	{
		cout << "最后一个字符不是运算符,Error!" << endl;
		return 2;
	}

	return 0;
}

int process(vector & sVector , double &result)
{
	int iErrorCode = 0;
	Stack_VT stack_str; 
	string cur_oper;
	vector::iterator iter = sVector.begin();

	for (vector::iterator iter = sVector.begin();
		(iter != sVector.end()) && (0 == iErrorCode);
		iter++)
	{
		//不是操作符就压入栈中,直到遇到操作符
		if (vOperator.cend() == find(vOperator.cbegin(), vOperator.cend(), (*iter)[0]))
		{
			stack_str.push(*iter);				
		}
		else
		{
			//保存当前的运算符
			cur_oper = *iter;

			//不光进行运算,还将已经用过的数字剔除掉,并将新的结果压入,即会改变stack_str
			iErrorCode = cal(stack_str, cur_oper, result);
		}
	}

	return iErrorCode;
}

int cal(Stack_VT &stack_str, string const &cur_oper, double &result)
{
	int iErrorCode = 0;
	double d1, d2;

	//因为只支持二目运算符,所以stack_str中必须至少包含两个数字
	if (stack_str.size() < 2)
	{
		iErrorCode = 3; 
		cout << "栈中的数字太少!" << endl;
		stack_str.print(cout);
	}

	if (0 == iErrorCode)
	{
		d1 = atof(stack_str.top().c_str());
		stack_str.pop();//用了就扔

		d2 = atof(stack_str.top().c_str());
		stack_str.pop();

		char oper = cur_oper[0];
		switch (oper)
		{
		case '+':
			result = d1 + d2;
			break;
		case '-':
			result = d1 - d2;
			break;
		case '*':
			result = d1*d2;
			break;
		case '/':
			if (d2 == 0.0)
			{
				iErrorCode = 4;
				result = 0;
			}
			else
			{
				result = d1 / d2;
			}
			break;
		default:
			iErrorCode = 5;
			break;
		}
		char result_str[10];
		sprintf_s(result_str, 10,"%.3lf", result);
		stack_str.push(result_str);

		//stack_str.print(cout);
	}

	return iErrorCode;
}

main.cpp:主函数,调用我们编写的函数

/********************************************************/
// 主函数
// 用于测试编写的各函数与数据结构
/********************************************************/
#include "SeqStack_VT_Def.h"
#include "postfix.h"
int main()
{
	/********************************************************/
	// 2,《数据结构与算法分析》3.6.3节 后缀记法的实现
	/********************************************************/
	string str = "6 5 2 3+8*+3+*";
	
	cout << "result = " << postfix_cal(str) << endl;
	
	system("pause");
	return 0;
}


运行结果如下:

数据结构学习笔记2——用栈计算后缀(postfix)表达的完整代码_第2张图片


你可能感兴趣的:(学习笔记)