#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版)的更多相关文章

  1. 深入浅出数据结构C语言版(8)——后缀表达式、栈与四则运算计算器

    在深入浅出数据结构(7)的末尾,我们提到了栈可以用于实现计算器,并且我们给出了存储表达式的数据结构(结构体及该结构体组成的数组),如下: //SIZE用于多个场合,如栈的大小.表达式数组的大小 #de ...

  2. Python与数据结构[1] -> 栈/Stack[1] -> 中缀表达式与后缀表达式的转换和计算

    中缀表达式与后缀表达式的转换和计算 目录 中缀表达式转换为后缀表达式 后缀表达式的计算 1 中缀表达式转换为后缀表达式 中缀表达式转换为后缀表达式的实现方式为: 依次获取中缀表达式的元素, 若元素为操 ...

  3. 中缀表达式转后缀表达式(用于求字符串表达式值)(js栈和队列的实现是通过数组的push和unshift方法插值,pop方法取值)

    中缀表达式:就是我通常用的算术或逻辑公式: 后缀表达式:不包含括号,运算符放在两个运算对象后面,所有的计算按运算符出现的顺序,严格从左向右进行,不用考虑运算符优先级: 如,(2+1)*3 转换后,2 ...

  4. javascript使用栈结构将中缀表达式转换为后缀表达式并计算值

    1.概念 你可能听说过表达式,a+b,a+b*c这些,但是前缀表达式,前缀记法,中缀表达式,波兰式,后缀表达式,后缀记法,逆波兰式这些都是也是表达式. a+b,a+b*c这些看上去比较正常的是中缀表达 ...

  5. 《java数据结构与算法》笔记-CH4-8栈结构实现后缀表达式计算结果

    /** * 中缀表达式转换成后缀表达式: 从输入(中缀表达式)中读取的字符,规则: 操作数: 写至输出 左括号: 推其入栈 右括号: 栈非空时重复以下步骤--> * 若项不为(,则写至输出: 若 ...

  6. 栈的应用1——超级计算器(中缀与后缀表达式)C语言

    这里要学的程序主要用来实现一个功能——输入表达式输出结果,也就是一个计算器.效果如下: 这个程序主要有两个步骤:1.把中缀表达式转换为后缀表达式:2.计算后缀表达式的结果. 首先先明白几个问题: 1. ...

  7. 栈应用之 后缀表达式计算 (python 版)

    栈应用之 后缀表达式计算 (python 版) 后缀表达式特别适合计算机处理 1.  中缀表达式.前缀表达式.后缀表达式区别  中缀表达式:(3 - 5) * (6 + 17 * 4) / 3 17 ...

  8. c++实验4 栈及栈的应用+回文+中、后缀表达式

    栈及栈的应用+回文+中.后缀表达式 1.栈顺序存储结构的基本操作算法实现 (1)栈顺序存储结构的类定义: class SeqStack { private: int maxsize; DataType ...

  9. 数据结构(3) 第三天 栈的应用:就近匹配/中缀表达式转后缀表达式 、树/二叉树的概念、二叉树的递归与非递归遍历(DLR LDR LRD)、递归求叶子节点数目/二叉树高度/二叉树拷贝和释放

    01 上节课回顾 受限的线性表 栈和队列的链式存储其实就是链表 但是不能任意操作 所以叫受限的线性表 02 栈的应用_就近匹配 案例1就近匹配: #include <stdio.h> in ...

随机推荐

  1. java中垃圾回收机制和引用类型

    在java中JDK1.2版本以后,对象的引用类型分为四种,从高到低依次为:强引用.软引用.弱引用.虚引用. ①强引用的特点:垃圾回收机制绝不会回收它,即使内存不足时,JVM宁愿抛出OutOfMemor ...

  2. nuxt项目踩坑

    1.window or document is not undefined // .vue 页面 if (process.browser) { var Distpicker = require('v- ...

  3. [cogs2701]动态树

    题面戳我 sol 比较裸啊. 注意操作顺序就行了. code #include<cstdio> #include<algorithm> using namespace std; ...

  4. C#多线程编程(6)--线程安全2 互锁构造Interlocked

    在线程安全1中,我介绍了线程同步的意义和一种实现线程同步的方法:volatile.volatile关键字属于原子操作的一种,若对一个关键字使用volatile,很多时候会显得很"浪费&quo ...

  5. 文件导出也可以这么写【js+blob】

    文件导出在软件开发中是个比较常用的功能,基本原理也很简单: 浏览器向后台发送一个Get请求 后台处理程序接收到请求后,经过处理,返回二进制文件流 浏览器接收到二进制文件流后提示下载文件 调用的js方法 ...

  6. CYQ.data 框架结构

    -------------------------V5.0开始(刚开始过滤版本:有些更新功能迁到V4,所以记录在V4那)-----------------------------7:Insert方法增 ...

  7. Google Chrome Plus——绿色便携多功能谷歌浏览器

    我更新浏览器的时候一般没有时间更新这个帖子,所以具体请看我网盘下载链接里面的更新日志,请自行查看最新版本下载,谢谢. 近期更新日期:2016.8.15(此时间可能不是最新,请看我网盘里面的更新日志) ...

  8. 记一次 synchronized 锁字符串引发的坑兼再谈 Java 字符串

    业务有一个需求,我把问题描述一下: 通过代理IP访问国外某网站N,每个IP对应一个固定的网站N的COOKIE,COOKIE有失效时间. 并发下,取IP是有一定策略的,取到IP之后拿IP对应的COOKI ...

  9. segment fault异常及常见定位手段

    问题背景 最近boot中遇到个用户态程序的segment fault异常,除了一句"Segment fault"打印外无其他任何打印.该问题复现概率较低,定位起来比较棘手.我们的b ...

  10. 用JNDI连接数据库

    之前说到了利用Java中的Properties类读取properties配置文件,连接数据库,现在说另一种方法,他们的目的和作用都是一样的,都是为了提高代码的复用性,解决了更改数据库 时还要更改代码的 ...