C++ 中缀表达式转后缀表达式

关于后缀表达式如何计算,这里不做过多叙述。以下提供两种方式供参考,第二个种方式粗略的写了计算方式。

方式一 —— 栈

该方式主要是通过栈的数据结构,规定运算符的优先级进行处理即可。
参考链接:https://blog.csdn.net/liudongdong19/article/details/80767156

源码(C++)

#include <iostream>
#include <map>
#include <string>
#include <stack>using namespace std;
map<char, int> priority;bool JudgeNumber(char s) { return s - '0' >= 0 && s - '0' <= 9 ? true : false; }int GetPriority(char c)
{auto iter = priority.find(c);return iter == priority.end() ? -1 : iter->second;
}string GetSuffix(string prefixStr)
{string suffixStr;stack<char> s;s.push('#');while (!prefixStr.empty()){//如果是数字或者小数那么直接加入后缀表达式if (JudgeNumber(prefixStr[0]) || prefixStr[0] == '.'){suffixStr.push_back(prefixStr[0]);prefixStr.erase(prefixStr.begin());}else{//当中缀表达式第一个字符为左括号时不进行判断   if (!suffixStr.empty()){//只有上一个数是数字,才添加空格;否则的话数字和数字之间不会有空格,也就无法区分是否为同一个数字if (JudgeNumber(suffixStr.back()))suffixStr.push_back(' ');}//如果是右括号的话,输出所有的操作运算符直至遇到左括号,并抛弃这一对括号if (prefixStr[0] == ')'){while (s.top() != '('){suffixStr.push_back(s.top());s.pop();suffixStr.push_back(' ');}prefixStr.erase(prefixStr.begin());s.pop();}else if (prefixStr[0] == '(')//如果是左括号的话,直接入栈{s.push(prefixStr[0]);prefixStr.erase(prefixStr.begin());}else if (GetPriority(prefixStr[0]) > GetPriority(s.top()))//如果中缀表达式中符号的优先级大于栈顶的符号优先级则直接入栈{s.push(prefixStr[0]);prefixStr.erase(prefixStr.begin());}else if (GetPriority(prefixStr[0]) <= GetPriority(s.top()))//如果中缀表达式中符号的优先级小于等于栈顶符号的优先级那么直接将栈中运算符添加至后缀表达式中。如果遇到左括号,则停止出栈,否则所有数据均出栈{while (s.top() != '(' && s.top() != '#'){suffixStr.push_back(s.top());suffixStr.push_back(' ');s.pop();}s.push(prefixStr[0]);prefixStr.erase(prefixStr.begin());}}}while (s.top() != '#'){suffixStr.push_back(' ');suffixStr.push_back(s.top());s.pop();}return suffixStr;
}int main()
{priority = { {'#',0},{'(',1}, {'+',3},{'-',3} ,{'*',5},{'/',5},{')',6} };//string s = "2*(3*5+2)+7/1-4";//string s = "8+4-6*2";//string s = "2*(3+5)+7/1-4";//string s = "12*(3+4)-6+8/2";string s = "(2+3)*2";cout << GetSuffix(s) << endl;return 0;
}

方式二 —— 二叉树

思路如下(以下思路仅供参考):

  比如对于中缀表达式:2*(3*5+2)+7/1-4,我们使用一个vector<string>的动态数组存储数字(整型和非整数);使用stack<char>存储运算符号,由于优先级的关系,我们使用’#'来表示最低优先级(其它符号均可)。

  现假定动态数组vector<string> arr和stack<char> s,一开始第一轮我们将2插入至arr,‘*‘的优先级比’#‘高,直接插入s中,但是由于当前没有两个以上数字,所以我们继续处理中缀表达式,s中插入’(‘运算符,之后一直处理数字和符号(s中如果有’(‘运算符则直接无条件插入),直至遇到’)‘符号,此时,当前arr = {2,3,5,2},s = {’#’,‘*’,‘(’,‘*’,‘+’};我们对括号中的符号以及相应数字进行处理,结果如下:

  此时中缀表达式只剩下:+7/1-4。继续处理,如下:

  最后,将剩余的符号和数字进行处理。

源码(C++)

#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <map>
#include <algorithm>using namespace std;
static map<char, int> priority;//二叉树结构
struct TreeNode
{TreeNode* left;TreeNode* right;string val;TreeNode(string val_) :left(nullptr), right(nullptr), val(val_) {};
};//判断是否为数字
static bool JudgeNumber(char s) { return s - '0' >= 0 && s - '0' <= 9 ? true : false; }//判断优先级
static int GetPriority(char c)
{auto iter = priority.find(c);return iter == priority.end() ? -1 : iter->second;
}//判断当前栈中是否包含'('操作符
static bool IsLeftSymbol(stack<char> stacks)
{while (!stacks.empty()){if (stacks.top() == '(')return true;stacks.pop();}return false;
}//在当前节点的右子树最下方重新构建一个单元的二叉树,
//比如:
//     +
//    / \
//   3   5
//如果c='*',rightNum=8,则
//    +
//   / \
//  3   *
//    /  \
//   5    8
void SetRightTree(TreeNode* curNode, char c, string rightNum)
{stack<TreeNode*> stacks;while (curNode->right != nullptr){stacks.push(curNode);curNode = curNode->right;}TreeNode* node = new TreeNode(string(1, c));node->left = stacks.top()->right;node->right = new TreeNode(rightNum);stacks.top()->right = node;
}//在当前节点上方重新构建一个单元的二叉树,
//比如:
//    +
//   / \
//  5   6
//如果s = {#,-},arr = {6};则
//    -
//   / \
//  +   6
// / \
//5   6
void SetTopTree(stack<char>& s, vector<string>& arr, TreeNode*& curNode)
{if (arr.size() == 0)return;TreeNode* node = new TreeNode(string(1, s.top()));s.pop();node->left = curNode;node->right = new TreeNode(arr[arr.size() - 1]);arr.pop_back();curNode = node;
}//设计一个单元的二叉树(一个父节点,两个子节点)
void SetRootNode(stack<char>& s, vector<string>& arr, TreeNode*& curNode)
{curNode = new TreeNode(string(1, s.top()));s.pop();curNode->left = new TreeNode(arr[arr.size() - 1]);arr.pop_back();curNode->right = new TreeNode(arr[arr.size() - 1]);arr.pop_back();
}//根据不同的情况(运算符的优先级)构建不同的二叉树单元
void SetTree(stack<char>& s, vector<string>& arr, TreeNode*& curNode, bool flag)
{if (curNode == nullptr)SetRootNode(s, arr, curNode);else if (GetPriority((curNode->val[0])) < GetPriority(s.top()) && !flag)//如果当前父节点的优先级小于栈顶运算符的优先级{SetRightTree(curNode, s.top(), arr[arr.size() - 1]);s.pop();arr.pop_back();}else if (GetPriority((curNode->val[0])) >= GetPriority(s.top()) || flag)//如果当前父节点的优先级大于等于栈顶运算符的优先级SetTopTree(s, arr, curNode);
}//构建二叉树,用于计算中缀表达式
TreeNode* GetPrefixTree(string str)
{TreeNode* beginNode = nullptr;vector<string> arr;stack<char> s;s.push('#');bool flag = false;while (!str.empty()){//如果当前不存在'('符号且beginNode未初始化,同时arr中有两个数字。(保证第一次直接构架一个基础二叉树单元)if (!IsLeftSymbol(s) && beginNode == nullptr && arr.size() == 2)SetRootNode(s, arr, beginNode);//如果是数字或者小数那么直接记录下来if (JudgeNumber(str[0])){int count = 0;while (count < str.size()){if (str[count] == '.' || JudgeNumber(str[count]))count++;else break;}arr.push_back(string(str.begin(), str.begin() + count).c_str());str.erase(str.begin(), str.begin() + count);}else//此时为运算符(+,-,*,/)或者'('和')'{if (str[0] == ')')//如果为')'符号,则处理当前数据{str.erase(str.begin());//去除')'while (s.top() != '#'){if (s.top() == '('){s.pop();flag = true;continue;}SetTree(s, arr, beginNode, flag);//构建二叉树}if (GetPriority(str[0]) >= GetPriority(beginNode->val[0]))//这个是用于判断比如(3+5)*2和2*(3+5),即如果括号在右侧,flag为true,此时不需要按照优先级判断。flag = true;elseflag = false;}else if (str[0] == '(')//此时无条件入栈{s.push(str[0]);str.erase(str.begin());}else if (IsLeftSymbol(s))//如果栈中有'('符号,则运算符号直接入栈{s.push(str[0]);str.erase(str.begin());}else if (GetPriority(str[0]) >= GetPriority(s.top()))//如果当前表达式中的符号优先级大于等于栈顶符号优先级{//如果此时二叉树中已经有节点,则接着处理if (beginNode != nullptr && s.top() != '#')SetTopTree(s, arr, beginNode);s.push(str[0]);str.erase(str.begin());}else if (GetPriority(str[0]) < GetPriority(s.top()))//如果当前表达式中的符号优先级小于栈顶符号优先级{SetTree(s, arr, beginNode, flag);s.push(str[0]);str.erase(str.begin());}}}if (beginNode != nullptr)//将最后剩余的元素进行处理SetTree(s, arr, beginNode, flag);return beginNode;
}//计算二叉树
double GetValue(TreeNode* node)
{if (!JudgeNumber(node->val[0])){if (node->val == "+")return GetValue(node->left) + GetValue(node->right);else if (node->val == "-")return GetValue(node->left) - GetValue(node->right);else if (node->val == "*")return GetValue(node->left) * GetValue(node->right);elsereturn GetValue(node->left) / GetValue(node->right);}elsereturn atof(node->val.c_str());
}int main()
{priority = { {'#',0},{'(',1}, {'+',3},{'-',3} ,{'*',5},{'/',5},{')',6} };//string s = "2*(3+5)+7/1-4";//string s = "8+4-6*2";//string s = "2.4234*(3+5)+7/1-4";string s = "2*(3*5+2)+7/1-4";//string s = "12*(3+4)-6+8/2";//string s = "(2+3)*2";TreeNode* node = GetPrefixTree(s);double  res = GetValue(node);cout << GetValue(node) << endl;return 0;
}

C++ 中缀表达式转后缀表达式(两种方式:栈、二叉树)相关推荐

  1. C++ string获取文件路径文件名、文件路径、文件后缀(两种方式)

    windows路径有两种方式,一种正斜杠,一种反斜杠都可以表示路径,该方法可以支持这两种表达方法 方法一:采用substr()进行分割 string path1 = "D:/datas/Fu ...

  2. BFS和DFS两种方式实现二叉树的层序遍历

    二叉树文章系列: 二叉树的前序遍历 二叉树的中序遍历 二叉树的后序遍历 二叉树的层序遍历 二叉树的前序.中序.后序.层序遍历[解法完整版] 本文目录 前言 一.题目 二.思路分析 解法一:广度优先搜索 ...

  3. java获取文件后缀_Java获取文件后缀的两种方式

    在对文件进行操作的时候,我们经常需要用到文件的后缀.但是Java API中并没有提供获取文件后缀的方法.下面的工具方法可以帮助我们实现这个目的. 方法1 代码示例: package org.4spac ...

  4. 数据结构 - 栈 (逆波兰计算器)(栈的三种表达式)(前缀、中缀和后缀表达式,后缀也叫逆波兰表达式)(中缀表达式转后缀表达式实现步骤及完整代码)

    栈的三种表达式:前缀.中缀和后缀表达式,后缀也叫逆波兰表达式 前缀(波兰表达式) 中缀(对人来讲很好理解,对于计算机来讲就方便了,一般会把中缀表达式转换成后缀表达式) 后缀(逆波兰表达式) 计算过程 ...

  5. java中缀表达式转后缀表达式_数据结构Java实现06----中缀表达式转换为后缀表达式...

    本文主要内容: 表达式的三种形式 中缀表达式与后缀表达式转换算法 一.表达式的三种形式: 中缀表达式:运算符放在两个运算对象中间,如:(2+1)*3.我们从小做数学题时,一直使用的就是中缀表达式. 后 ...

  6. 数据结构——栈——中缀表达式和后缀表达式

    什么是中缀表达式,什么是后缀表达式 我们一般看见的多项式计算都是中缀表达式构成的:1+2*3+4/3 类似这种,为什么说是中缀呢?因为它的计算符号都是在两个数中间的. 那么自然而然的明白了后缀表达式是 ...

  7. 【Weiss】【第03章】练习3.20:中缀表达式转后缀表达式

    [练习3.20] a.编写一个程序将中缀表达式转换为后缀表达式,该中缀表达式含括号及四则运算. b.把幂操作符添加到你的指令系统中去. c.编写一个程序将后缀表达式转化为中缀表达式. Answer: ...

  8. 栈应用(中缀表达式转后缀表达式并计算后缀表达式的值)

    [0]README 0.1) 本文旨在总结 中缀表达式转后缀表达式并计算后缀表达式的值 的步骤,并给出源代码实现: 0.2) 本文中涉及到的源代码均为原创,是对中缀转后缀和计算后缀的简单实现,(旨在理 ...

  9. 逆波兰式 java_逆波兰式(后缀表达式)的计算 中缀表达式转后缀表达式(逆波兰式)【java实现】...

    一.逆波兰式(后缀表达式)计算 思路: * 1.遍历逆波兰式的集合 * 2.当遍历的元素为数字时,入栈 stack * 3.当遍历的元素为运算符时,stack栈弹出两个数,num2 num1,并用该运 ...

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

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

最新文章

  1. No mapping found for HTTP request with URI
  2. WPF 与Surface 2.0 SDK 亲密接触 - ScatterView 篇
  3. 《计算机图形学》2.1.7 立体感和虚拟现实系统
  4. 成为Java GC专家(5)—Java性能调优原则
  5. IntelliJ IDEA for Mac下载、安装、使用TunnelliJ插件(一种TCP/IP Monitor)
  6. LAB Color Space
  7. python 预测 位置_Python:核岭回归预测,KRR
  8. vim - multiple windows
  9. NDK 下利用 arm-linux-androideabi-addr2line 定位 so 库问题点
  10. oracle 判断非空字段
  11. 战地1服务器性能红色,FPS《战地1》PC性能测试:对显卡要求不高但很吃CPU
  12. 欧姆龙PLC 通过CJ1W-EIP21实现在线编程
  13. 数字证书如何写入到ukey_ukey身份认证步骤
  14. 今年-计划写一本java方面的书籍-初稿正式完成
  15. python 读excel每行替换_Python使用openpyxl读写excel文件
  16. SECS\GEM RMS系统OEE定义
  17. [附源码]SSM计算机毕业设计小型银行贷款管理系统JAVA
  18. 休谟问题和金岳霖的回答
  19. 【coq】函数语言设计 笔记 05 -tactics
  20. Maya插件教程(一)

热门文章

  1. 干货 | 找工作的经验总结(一)
  2. [论文翻译]Attention Is All You Need
  3. C/C++——求数组长度及反序
  4. 不愧是我,短短10分钟就为公司省下了几万块 ( ー̀◡ー́ )
  5. Drupal是基于PHP语言编写的用于开发网站的开发型CMF
  6. 从程序员到CTO也可以走捷径
  7. 5.5 卷积、卷积定理和傅里叶变换的关系及其性质
  8. Scala常用List列表操作方法
  9. Mysql中Drop,Truncate,Delete的区别
  10. numpy教程:随机数模块numpy.random