实现《数据结构与算法分析 C++描述》3.6.3节的“后缀表达式”算法。
后缀表达式是类似于这样的表达式:6 5 2 3 + 8 * + 3 + *
求值过程为:当遇到一个数字时就将其压入栈中,在遇到一个操作符时,该操作符就作用于从该栈弹出的两个数字上,再将所得结果压入栈中。
为实现这一算法,需要用到上一节实现的栈,当然,为了方便使用,我们给上一节的栈增加了一个成员函数size()用于返回栈的大小
文件结构如下:
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; //栈顶所在的数组下标
};
/********************************************************/
// 用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;
}
}
}
/********************************************************/
// 《数据结构与算法分析》3.6.3节 后缀记法的实现
/********************************************************/
#pragma once
#include "SeqStack_VT_Def.h"
double postfix_cal(string const& str);
/********************************************************/
// 《数据结构与算法分析》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;
}
/********************************************************/
// 主函数
// 用于测试编写的各函数与数据结构
/********************************************************/
#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;
}