关于使用栈将一般运算式翻译为后缀表达式并实现三级运算的方法及实例(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 ...
随机推荐
- POJ 1791 Heavy Transportation(最大生成树)
题面 Background Hugo Heavy is happy. After the breakdown of the Cargolifter project he can now expand ...
- Eclipse常用不常用快捷键
逼格高且常用的7个快捷键:Ctrl+O:列出该类下的所有方法 Ctrl+E:列出打开的所有类 Shift+Enter:在当前行下一行创建空白行(Ctrl+Shift+Enter:在当前行上一行 ...
- Nginx负载均衡——扩展功能(NGINX Plus)
本文主要是介绍了NGINX Plus的相关功能,横跨了NGINX Plus R5/R6/R7/R9等各个不同版本的更新. 什么是NGINX Plus? 顾名思义,就是Nginx的加强版或者扩展版.我们 ...
- 【经验随笔】MYSQL表加锁升级导致数据库访问失败
背景:有一次定位问题发现,在同一个session连接中对MYSQL部分表加锁,导致其它未加锁的表不能访问. 用Spring管理MYSQL数据连接,在多线程访问数据库的情况下容易出问题.一个线程中对部分 ...
- JavaScript ES6 的let和const
1 作用域和提升 1.1 作用域(Scope) 某个变量名或者函数名,在某个程序片段中是否可见或者可访问,如果是,那么这个程序片段就是这个变量名或者函数名的作用域.比如: var name = &qu ...
- Android RecyclerView 滚动到中间位置
最近看到QQ音乐的歌词每次滑动后都可以滚回到中间位置.觉得甚是神奇,打开开发者模式显示布局,发现歌词部分不是采用 android 控件的写的,应该是前端写的.于是,我想,能不能用 recyclerVi ...
- 图像实验室 website 项目日志
day 1 1.问题: 在演示界面选择浏览本地图片,上传以后不显示上传图片 原因:PIL库没有装好,参见之前博客重装 2.问题: 可以上传图片并在网站上显示,但是不能得到运行结果的图片. 原因:没有将 ...
- Jersey+mybatis实现web项目第一篇
---恢复内容开始--- Jesery第一篇:实现Jesery前后台页面交互,Form表单提交,后台控制页面跳转 该项目中有实现的功能: Mybatis实现后台数据持久化 Jersey页面数据提交 后 ...
- 本站已稳定运行了XX天,网页时间显示功能实现方法
这个是我昨晚上添加的效果, 分为三个部分: 1.本站已稳定运行了多少天的实现: 直接把下面代码复制到后台你想添加的位置即可. 1 2 3 4 5 6 7 8 9 本站已稳定运行了 <strong ...
- 浅析JavaScript的prototype
一.JavaScript对象的创建 (1)对象方法 function Student(name){ this.name=name; this.showName=function(){ alert(&q ...