最近学习数据结构,说到栈结构的一大应用就是基于后缀表达式的四则运算求值,那么什么是后缀表达式呢?让我们来简单举个栗子:
比如我们正常的数学表达式 3+1,我们称这种表达式为中缀表达式
其后缀表达式为3 1 +,嗯…,没错,就是把运算符号写在相互运算的两个数字的后面
我们再来一个复杂的栗子,中缀表达式:9*3+(10-4)*2-15/3 这样一个表达式,他的后缀表达式是什么样子的呢?让我们来一步一步分析一下吧
根据算法优先级可以分析出:
第一个*号相乘的两个数字为 9 和 3,其后缀表达式可以表示为9 3 *
第一个-号相减的数字为10 和 4,其后缀表达式可以表示为10 4 -
第二个*号相乘的两个数字为(10-4)的结果 和 2,故(10-4)*2的后缀表达式为10 4 - 2 *
第一个/号相除的两个数字为15和3,其后缀表达式可以表示为15 3 /
接下来是加号了,其两边操作数为9*3 和 (10-4)*2,故其后缀表达式为:
9 3 * 10 4 - 2 * +
最后,对于最后一个-号,其两端操作数分别为9*3+(10-4)*2 和 15/3 的结果,故最终表达式9*3+(10-4)*2-15/3的后缀表达式为:
9 3 * 10 4 - 2 * + 15 3 / -
以上为后缀表达式的原理分析过程,下面来讲解一下由中缀表达式获取后缀表达式的求解规则:
从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后最表达式的一部分;若是符号,则判断其与栈顶符号的优先级,若是右括号,或优先级不高于栈顶符号,则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。
现在我们得到了中缀表达式了,那么我们怎么求值呢?这里我们同样需要一个栈结构辅助,用于管理数值的进出,其执行规则如下:
从左到右遍历后缀表达式的每个数字和符号,若是数字就进栈,若是符号,就将处于栈顶的两个元素出栈,进行运算,然后将结果进栈,一直到最终获得结果
前面说明了原理,接下来直接上代码了,我基于此实现了一个四则运算类,其定义如下:
#pragma once
#include <string>
#include"RL_Stack.h"
#include <map>
#include <queue>
namespace RL
{
class QuadricOperation
{
public:
// 定义运算符优先级
const std::map<std::string, int> m_operator_priority =
{
{"+",1},{ "-",1 },{ "*",2 },{ "/",2 }
};
public:
QuadricOperation();
~QuadricOperation();
void SetExpression(const std::string &); // 设置中缀表达式
double GetValue(); // 获取最后结果
//std::queue<std::string> GetPrefixExpression(); //
std::queue<std::string> GetInfixExpression();// 获取后缀表达式
private:
// 中缀表达式转后缀表达式
void calculation_infix_expression();
void calculation_symbol_stack(std::string _str);
// 使用后缀表达式进行求值
void calculation_result();
private:
//std::string m_prefix_expression; // 前缀表达式
//std::string m_infix_expression; // 中缀表达式
std::queue<std::string> m_prefix_expression; // 中缀表达式
std::queue<std::string> m_infix_expression; // 后缀表达式
LinkStack<std::string> m_symbol_stack; // 符号栈
LinkStack<double> m_value_stack; // 数值栈
double m_result; // 计算结果
bool m_is_calculated; // 是否已经计算过了
};
}
其实现代码如下:
#include "stdafx.h"
#include "QuadricOperation.h"
//#include
namespace RL
{
QuadricOperation::QuadricOperation()
{
}
QuadricOperation::~QuadricOperation()
{
}
void QuadricOperation::SetExpression(const std::string &expression)
{
m_is_calculated = false;
std::string vel = "";
for (int i = 0; i < expression.length(); i++)
{
if ((expression[i] >= '0' && expression[i] <= '9') || expression[i] == '.')
{
vel += expression[i];
}
else
{
if (vel.length()>0)
{
m_prefix_expression.push(vel);
vel = "";
}
std::string _vel = "";
_vel+=expression[i];
m_prefix_expression.push(_vel);
}
}
if (vel.length()>0)
{
m_prefix_expression.push(vel);
}
}
double QuadricOperation::GetValue()
{
if (!m_is_calculated)
{
if (m_infix_expression.empty())
{
calculation_infix_expression();
}
calculation_result();
m_is_calculated = true;
}
return m_result;
}
std::queue<std::string> QuadricOperation::GetPrefixExpression()
{
return m_prefix_expression;
}
std::queue<std::string> QuadricOperation::GetInfixExpression()
{
if (m_infix_expression.empty())
{
calculation_infix_expression();
}
return m_infix_expression;
}
void QuadricOperation::calculation_symbol_stack(std::string _str)
{
if (_str == "(")
{
m_symbol_stack.Push(_str);
return;
}
if (m_operator_priority.find(_str) != m_operator_priority.end())
{
if (m_symbol_stack.isEmpty())
{
m_symbol_stack.Push(_str);
return;
}
std::string _symbol;
m_symbol_stack.GetPop(_symbol);
if (_symbol == "(")
{
m_symbol_stack.Push(_str);
return;
}
while (!m_symbol_stack.isEmpty())
{
std::string _symbol;
m_symbol_stack.GetPop(_symbol);
if (_symbol == "(")
{
m_symbol_stack.Pop();
m_symbol_stack.Push(_str);
return;
}
if (m_operator_priority.at(_symbol) < m_operator_priority.at(_str))
{
m_symbol_stack.Push(_str);
return;
}
m_symbol_stack.Pop();
m_infix_expression.push(_symbol);
}
m_symbol_stack.Push(_str);
return;
}
if (_str == ")")
{
while (!m_symbol_stack.isEmpty())
{
std::string _symbol;
m_symbol_stack.GetPop(_symbol);
if (_symbol == "(")
{
m_symbol_stack.Pop();
//m_symbol_stack.Push(_str);
return;
}
m_symbol_stack.Pop();
m_infix_expression.push(_symbol);
}
}
}
void QuadricOperation::calculation_infix_expression()
{
while (!m_prefix_expression.empty())
{
std::string _str = m_prefix_expression.front();
m_prefix_expression.pop();
if (m_operator_priority.find(_str) == m_operator_priority.end() && _str != "("&& _str != ")")
{
m_infix_expression.push(_str);
continue;
}
calculation_symbol_stack(_str);
}
while (!m_symbol_stack.isEmpty())
{
std::string _symbol = m_symbol_stack.Pop();
m_infix_expression.push(_symbol);
}
}
void QuadricOperation::calculation_result()
{
while (!m_infix_expression.empty())
{
std::string _str = m_infix_expression.front();
m_infix_expression.pop();
if (m_operator_priority.find(_str) != m_operator_priority.end())
{
double _vel1 = m_value_stack.Pop();
double _vel2 = m_value_stack.Pop();
if (_str == "+")
{
m_value_stack.Push(_vel2 + _vel1);
}
if (_str == "-")
{
m_value_stack.Push(_vel2 - _vel1);
}
if (_str == "*")
{
m_value_stack.Push(_vel2 * _vel1);
}
if (_str == "/")
{
m_value_stack.Push(_vel2 / _vel1);
}
continue;
}
double _vel = atof(_str.c_str());
m_value_stack.Push(_vel);
}
m_result = m_value_stack.Pop();
}
}
另外说明一下,这里使用的栈是本人自己实现的栈结构,如果需要可以去这里获取:https://blog.youkuaiyun.com/m0_45074715/article/details/127721573
当然,你也可以给将相应代码改成你自己的或者标准库的栈