关于使用栈将一般运算式翻译为后缀表达式并实现三级运算的方法及实例(cpp版)
#include <iostream>
#include <stack>
#include <vector>
#include <string>
#define uint unsigned int
using namespace std;
//判断该字符是否为运算符 是则返回真 否则返回假
inline bool isOperator(char opr)
{
switch(opr)
{
case '*':
return true;
case '/':
return true;
case '+':
return true;
case '-':
return true;
default:
return false;
}
}
//Sufexp(string& ,vector<string>& ); //翻译为后缀表达式 suffic expression
//第一个参数为输入表达式字符串引用,第二个参数为放置后缀表达式的向量引用
//从首至尾分别为数字和运算符 没有检查功能
void Sufexp(string &str,vector<string> &str_vec)
{
stack<string,vector<string> > sta;
string::size_type longth = str.size();
int last_flag = -1;
for(int i = 0;i < longth;i++)
{
//如果第i个字符串是运算符 则进入大判断
if(str.at(i) == '*' || str.at(i) == '/' || str.at(i) == '+' || str.at(i) == '-' || str.at(i) == '(' || str.at(i) == ')'|| str.at(i) == '=')
{
//如果是左括号则需要改变last_flag
if(str.at(i) == '(' )
{
last_flag = i;
}
//如果右括号右边紧跟运算符则需要改变last_flag
else if(str.at(i-1) == ')' && isOperator(str.at(i)))
{
last_flag = i;
}
//遇到右括号紧跟等号也不需要分割 遇到右括号紧跟运算符不需要分割
else if(!((str.at(i-1) == ')' && str.at(i) == '=') || (str.at(i-1) == ')' && isOperator(str.at(i)))))
{
str_vec.push_back(str.substr(last_flag + 1,i - last_flag -1));
last_flag = i;
}
//如果栈为空 直接将符号入栈
if(sta.size()==0)
{
char ch[1] = {str.at(i)};
string str_1(ch,1);
sta.push(str_1);
}
//如果栈不为空
//如果检测到 '(' 直接入栈
else if(str.at(i) == '(')
{
char ch[] = {str.at(i)};
string str_1(ch,1);
sta.push(str_1);
}
//如果检测到的是高级运算符先将之前的高级弹出的字符串项链在将新运算符入栈
else if(str.at(i) == '*' || str.at(i) == '/')
{
if(sta.top() == "*" || sta.top() == "/")
{
str_vec.push_back(sta.top());
sta.pop();
}
char ch[] = {str.at(i)};
string str_1(ch,1);
sta.push(str_1);
}
//如果检测到的是低级运算符需要将高级运算符弹出 同级运算符也需要先弹出再入栈 低级运算符再入栈
else if(str.at(i) == '+' || str.at(i) == '-')
{
bool once = false ;
//判断之前的运算符是否为高级运算符 如果是
while((sta.top() == "*" || sta.top() == "/") && sta.size() != 0 )
{
//先将 高级 运算符弹出放入字符串向量
str_vec.push_back(sta.top());
sta.pop();
once = true;
if(sta.size() == 0) break;
}
//如果曾经把高级运算符弹出去过 就不用将现在栈顶运算符弹出了 否则就弹出一次
if(once == false && sta.size() != 0)
{
if(sta.top() == "+" || sta.top() == "-")
{
str_vec.push_back(sta.top());
sta.pop();
//if(sta.size() == 0) break;
}
}
//再将低级运算符压栈
char ch[] = {str.at(i)};
string str_1(ch,1);
sta.push(str_1);
}
//如果检测到 ')' 将栈中的符号逐个弹出 直至遇到 '('
else if(str.at(i) == ')')
{
while(sta.top() != "(")
{
str_vec.push_back(sta.top());
sta.pop();
if(sta.size() == 0) break;
}
//将'('直接弹出而不放入字符串向量
if(sta.top() == "(")
{
//cout << sta.top() << endl;
sta.pop();
}
}
//如果检测到是 '=' 将栈中数据全部弹出至字符串向量 最后将'='存入字符串向量
//输出后缀表达式
else if(str.at(i) == '=')
{
//将栈中数据全部弹出至字符串向量
while(sta.size() != 0)
{
str_vec.push_back(sta.top());
sta.pop();
}
//最后将'='存入字符串向量
str_vec.push_back("=");
vector<string>::iterator begin = str_vec.begin();
vector<string>::iterator end = str_vec.end();
//如果向量中有空字符串 可以去除有括号与运算符紧挨在一起由substr引起的空字符串
/*for( ;begin != str_vec.end(); begin++)
{
if((*begin) == "")
{
str_vec.erase(begin);
begin--;
}
}*/
//输出后缀表达式
/*cout << "后缀表达式:" << endl;
begin = str_vec.begin();
end = str_vec.end();
for( ;begin != end;begin++)
{
//显示第n个元素的下标与对应元素内容
cout << distance(str_vec.begin(),begin) << "\t" << *begin << endl;
}
cout << endl;*/
}
}
}
}
//向量内的元素遍历显示
void showVecFac(vector<string> str_vec)
{
vector<string>::iterator begin = str_vec.begin();
vector<string>::iterator end = str_vec.end();
for(;begin != end;begin++)
{
cout << *begin << "\t" ;
}
cout << endl;
}
//计算后缀表达式
void calSuf(vector<string> &str_vec)
{
//向量遍历
for(vector<string>::iterator begin = str_vec.begin();begin != str_vec.end();begin++)
{
vector<string>::iterator temp_begin = begin; //中间迭代器变量
const char *first_char;
const char *second_char;
string result;
char temp_str_result[50];
double temp_double;
const char *answer;
bool point = false;
uint last_num = 0;
uint i = 0;
//将字符串转换为char形
const char *temp_char = (*begin).c_str();
//处理基本运算
switch(*temp_char)
{
case '*':
//提取运算符前边两个数据 用于计算
--temp_begin;
second_char = (*temp_begin).c_str();
--temp_begin;
first_char = (*temp_begin).c_str();
//运算
temp_double = atof(first_char) * atof(second_char);
/*cout << "first_char : " << first_char << endl;
cout << "second_char : " << second_char << endl;
cout << temp_double << endl;*/
//将数据替换到begin
sprintf(temp_str_result, "%lf", temp_double);
result = temp_str_result;
(*begin) = result;
//清除空余数据
str_vec.erase(temp_begin);
begin--;
str_vec.erase(temp_begin);
begin--;
break;
case '/':
//提取运算符前边两个数据 用于计算
--temp_begin;
second_char = (*temp_begin).c_str();
--temp_begin;
first_char = (*temp_begin).c_str();
//运算
temp_double = atof(first_char) / atof(second_char);
//将数据替换到begin
sprintf(temp_str_result, "%lf", temp_double);
result = temp_str_result;
(*begin) = result;
//清除空余数据
str_vec.erase(temp_begin);
begin--;
str_vec.erase(temp_begin);
begin--;
break;
case '+':
//提取运算符前边两个数据 用于计算
--temp_begin;
second_char = (*temp_begin).c_str();
--temp_begin;
first_char = (*temp_begin).c_str();
//运算
temp_double = atof(first_char) + atof(second_char);
//将数据替换到begin
sprintf(temp_str_result, "%lf", temp_double);
result = temp_str_result;
(*begin) = result;
//清除空余数据
str_vec.erase(temp_begin);
begin--;
str_vec.erase(temp_begin);
begin--;
break;
case '-':
//提取运算符前边两个数据 用于计算
--temp_begin;
second_char = (*temp_begin).c_str();
--temp_begin;
first_char = (*temp_begin).c_str();
//运算
temp_double = atof(first_char) - atof(second_char);
//将数据替换到begin
sprintf(temp_str_result, "%lf", temp_double);
result = temp_str_result;
(*begin) = result;
//清除空余数据
str_vec.erase(temp_begin);
begin--;
str_vec.erase(temp_begin);
begin--;
break;
case '=':
//判断结构是否为小数
//判断是否为整数
answer = (*(begin-1)).c_str();
point = false;
last_num = 0;
i = 0;
while(answer[i])
{
if(answer[i] == '.')
{
point = true;
}
if(point == true && answer[i] != '0')
{
last_num = i;
}
i++;
}
//判断最后一位是不是小数点 区别对待
if(answer[last_num] == '.')
{
--last_num;
}
*(begin-1) = (*(begin-1)).substr(0,last_num + 1);
break;
default:
break;
}
}
//清除末尾的等号 只存储最终结果
str_vec.erase(str_vec.end()-1);
}
//用于输出结果
void showAnswer(vector<string> & str_vec)
{
cout << "the result is : " << *(str_vec.begin()) << endl;
}
int main()
{
string str;
cin >> str;
//末尾自动添加 等号
str += "=";
//用于存放后缀表达式
vector<string> str_vec;
//通过函数 得到后缀表达式的向量 存放在str_vec向量中
//第一个参数为输入表达式字符串引用,第二个参数为放置后缀表达式的向量引用,从首至尾分别为数字和运算符
//没有检查功能
Sufexp(str,str_vec);
//计算后缀表达式 并存放在str_vec向量中
calSuf(str_vec);
showAnswer(str_vec);
//直接输入运算符可以借用上一次结果继续运算
while(1)
{
cin >> str;
str += "=";
//如果紧跟上次的结果的是运算符 就接着运算 否则展开新运算与上次结果无关
if(str.at(0) == '*' || str.at(0) == '/' || str.at(0) == '+' || str.at(0) == '-')
{
str = (*(str_vec.end()-1)) + str;
}
str_vec.clear();
Sufexp(str,str_vec);
//计算后缀表达式 并存放在str_vec向量中
calSuf(str_vec);
showAnswer(str_vec);
}
return 0;
}
关于使用栈将一般运算式翻译为后缀表达式并实现三级运算的方法及实例(cpp版)的更多相关文章
- 深入浅出数据结构C语言版(8)——后缀表达式、栈与四则运算计算器
在深入浅出数据结构(7)的末尾,我们提到了栈可以用于实现计算器,并且我们给出了存储表达式的数据结构(结构体及该结构体组成的数组),如下: //SIZE用于多个场合,如栈的大小.表达式数组的大小 #de ...
- Python与数据结构[1] -> 栈/Stack[1] -> 中缀表达式与后缀表达式的转换和计算
中缀表达式与后缀表达式的转换和计算 目录 中缀表达式转换为后缀表达式 后缀表达式的计算 1 中缀表达式转换为后缀表达式 中缀表达式转换为后缀表达式的实现方式为: 依次获取中缀表达式的元素, 若元素为操 ...
- 中缀表达式转后缀表达式(用于求字符串表达式值)(js栈和队列的实现是通过数组的push和unshift方法插值,pop方法取值)
中缀表达式:就是我通常用的算术或逻辑公式: 后缀表达式:不包含括号,运算符放在两个运算对象后面,所有的计算按运算符出现的顺序,严格从左向右进行,不用考虑运算符优先级: 如,(2+1)*3 转换后,2 ...
- javascript使用栈结构将中缀表达式转换为后缀表达式并计算值
1.概念 你可能听说过表达式,a+b,a+b*c这些,但是前缀表达式,前缀记法,中缀表达式,波兰式,后缀表达式,后缀记法,逆波兰式这些都是也是表达式. a+b,a+b*c这些看上去比较正常的是中缀表达 ...
- 《java数据结构与算法》笔记-CH4-8栈结构实现后缀表达式计算结果
/** * 中缀表达式转换成后缀表达式: 从输入(中缀表达式)中读取的字符,规则: 操作数: 写至输出 左括号: 推其入栈 右括号: 栈非空时重复以下步骤--> * 若项不为(,则写至输出: 若 ...
- 栈的应用1——超级计算器(中缀与后缀表达式)C语言
这里要学的程序主要用来实现一个功能——输入表达式输出结果,也就是一个计算器.效果如下: 这个程序主要有两个步骤:1.把中缀表达式转换为后缀表达式:2.计算后缀表达式的结果. 首先先明白几个问题: 1. ...
- 栈应用之 后缀表达式计算 (python 版)
栈应用之 后缀表达式计算 (python 版) 后缀表达式特别适合计算机处理 1. 中缀表达式.前缀表达式.后缀表达式区别 中缀表达式:(3 - 5) * (6 + 17 * 4) / 3 17 ...
- c++实验4 栈及栈的应用+回文+中、后缀表达式
栈及栈的应用+回文+中.后缀表达式 1.栈顺序存储结构的基本操作算法实现 (1)栈顺序存储结构的类定义: class SeqStack { private: int maxsize; DataType ...
- 数据结构(3) 第三天 栈的应用:就近匹配/中缀表达式转后缀表达式 、树/二叉树的概念、二叉树的递归与非递归遍历(DLR LDR LRD)、递归求叶子节点数目/二叉树高度/二叉树拷贝和释放
01 上节课回顾 受限的线性表 栈和队列的链式存储其实就是链表 但是不能任意操作 所以叫受限的线性表 02 栈的应用_就近匹配 案例1就近匹配: #include <stdio.h> in ...
随机推荐
- css样式--表格
1.示例源码 <!DOCTYPE html><html><head><meta charset="utf-8"> <title ...
- 【Luogu2759】奇怪的函数(数论)
[Luogu2759]奇怪的函数(数论) 题面 题目描述 使得 \(x^{x}\)达到或超过 n 位数字的最小正整数 x 是多少? 输入输出格式 输入格式: 一个正整数 n 输出格式: 使得 \(x^ ...
- 【NOIP2015】斗地主(搜索,贪心)
题面戳我 题解 我原来也觉得是一道不可做的难题.. 其实,,,很简单的啦... 对于当前状态 我们出牌的方式大致分为两类 一类是不用考虑点数的,包括单张,对子,三带一等 另一类就是需要考虑点数的,包括 ...
- web前端UI框架
分类:WEB前端 时间:2016年1月13日 目前,众多互联网公司APP都嵌入了大量的HTML5,移动端的开发越来越重视,HTML5的运用场景也越来越多了.在移动WEB开发的过程中,使用合适的移动WE ...
- angular路由详解五(辅助路由)
在HTML文件中 //主路由 <router-outlet></router-outlet> //辅助路由 <router-outlet name="aux& ...
- Java NIO FileVisitor 高效删除文件
在公司项目中,由于做个二维码扫码平台项目,预计每天产生的二维码图片达到十几G,所以要做个定时清理任务来定时清理图片,根据不同场景保留图片,规则是:1.二维码统一登录图片几个小时有效 2.电子名片二 ...
- mysql 服务启动失败
mysql 数据库连接失败 1.用naviCat Preiumn 连接本地的mysql 失败,查找原因,mysql 数据库服务没有启用,但是在服务列表里面没有找到对应的mysql 服务. 所以在cmd ...
- Sharepoint Management Shell命令
1.普通WSP包,没有特殊激活内容 安装BBA.WebParts.wsp 1) Add-SPSolution -LiteralPath "c:\BBA.WebParts.wsp" ...
- (转)regex类(个人理解)
regex类(个人理解) C#regex是正则表达式类用于string的处理,查找匹配的字符串.1,先看一个例子Regex regex=new Regex(@”OK“)://我们要在目标字符串中找 ...
- CentOS 远程桌面相关服务安装笔记
# CentOS 7安装图形界面 sudo yum groupinstall "GNOME Desktop" "Graphical Administration Tool ...