前、中、后缀表达式和表达式树

前、中、后缀表达式和表达式树

前、中、后缀表达式的区别取决于操作符和操作数的位置:

1、前缀表达式:操作符在操作数前面,可通过前序遍历表达式树获得。

2、中缀表达式:操作符在操作数中间,可通过中序遍历表达式树获得(中缀表达式通过中序遍历得到后的括号是必须的)。

3、后缀表达式:操作符在操作数后面,可通过后序遍历表达式树获得。

表达式的二叉树(表达式树):

表达式树: 即用二叉树来表示代数表达式,数的每一个内部节点都代表一个运算符,每一个叶子结点代表一个运算符数。

构造: 对于给定的中缀表达式(即代数表达式),我们通过下面步骤进行构建表达式二叉树

1、建立两个栈,一个操作符栈,用来存放操作符,一个是操作数栈,用来存放操作数。

2、从左往右遍历中缀表达式。

3、遇到操作数,为该操作数建立新节点,其值为操作数的值,然后放入操作数栈中。

4、遇到操作符通过按照以下规则处理:

  • 如果当前操作符优先级大于操作符栈的顶部元素,直接入栈
  • 如果当前操作符优先级小于或等于操作符栈的顶部元素,先将顶部元素出栈再将当前操作符入栈
  • 当前操作符为左括号时直接入栈
  • 当前操作符为右括号时,让栈顶到左括号为止的操作符出栈,括号不出现在后缀表达式中

5、当操作符从操作符栈中出栈时,为该操作符新建一个新节点,并从操作数栈中出栈两个操作数节点,将这两个操作数作为该操作符节点的两个孩子,然后将这个新节点压入到操作数栈中,其值为两个操作数通过操作符后的结果。当最后一个操作符出栈时,就构成了表达式树,且最后一个操作符节点为根节点。

计算中缀表达式的值

1、建立两个栈,一个操作符栈,用来存放操作符,一个是操作数栈,用来存放操作数。

2、从左往右遍历中缀表达式。

3、遇到操作数放入操作数栈中。

4、遇到操作符通过按照以下规则处理:

  • 如果当前操作符优先级大于操作符栈的顶部元素,直接入栈
  • 如果当前操作符优先级小于或等于操作符栈的顶部元素,先将顶部元素出栈再将当前操作符入栈
  • 当前操作符为左括号时直接入栈
  • 当前操作符为右括号时,让栈顶到左括号为止的操作符出栈,括号不出现在后缀表达式中

5、在操作符出栈时从栈中取出两个数计算出值后将结果值压入操作数栈

中缀表达式转后缀表达式:

1、建立两个栈,一个操作符栈,用来存放操作符,一个是操作数栈,用来存放操作数。

2、从左往右遍历中缀表达式

3、遇到操作数直接输出

4、遇到操作符通过按照以下规则处理:

  • 如果当前操作符优先级大于操作符栈的顶部元素,直接入栈
  • 如果当前操作符优先级小于或等于操作符栈的顶部元素,先将顶部元素出栈再将当前操作符入栈
  • 当前操作符为左括号时直接入栈
  • 当前操作符为右括号时,让栈顶到左括号为止的操作符出栈,括号不出现在后缀表达式中

5、在遍历完中缀表达式后,让操作符栈的最后元素出栈即可

中缀表达式转前缀表达式:

1、建立两个栈,一个操作符栈S1,另一个是存储中间结果的栈S2

2、从右往左遍历中缀表达式

3、遇到操作数压入S2中

4、遇到操作符通过按照以下规则处理:

  • 如果操作符栈顶元素是右括号”)“,则直接压入S1中。
  • 如果操作符栈顶元素是左括号”(“,则依次弹出S1的运算符,并压入S2,直到遇到有括号为止,并且将S1中的这对括号都出栈丢弃。
  • 如果S1为空,则直接将运算符入栈
  • 如果当前运算符的优先级比S1中的栈顶元素的优先级较高或相等,压入S1
  • 如果当前运算符的优先级比S1中的栈顶元素的优先级低,将S1的栈顶运算符弹出并压入S2中。

5、重复2 到 5 操作,直到遍历到表达式最左端

6、将S1中剩余的运算依次弹出压入S2

7、依次弹出S2中的元素并输出,即是中缀表达式对应的前缀表达式。

表达树性质:

1、在表达树中,如果该结点向上走,即表示该子树的结点都被遍历完了(即该子树的值被算出来了),反之就是没有遍历完该子树。

2、当前内结点肯定相比其上一个结点的优先级更低。

根据1、2性质可以知道,通过栈模拟的时候,如果栈内的操作符的优先级比当前操作符的优先级高或者相等,即要把它们算出来,表示他们已经算过了(对应表达树中,该子树已经被遍历过了),然后再将计算后的值加入到操作数栈中。对于括号内的也是按照这个性质来进行的,当从左向右遍历遇到右括号,即表示括号内的部分已经要先计算出来,所以将括号内的内容都计算出来,然后再将计算后的值加入到操作数栈中即可。

中缀表达式求值代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <stack>
#include <unordered_map>
using namespace std;
stack<int>num;
stack<char>op;
string s;
unordered_map<char, int>pr{{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};
void eval(){
    int b = num.top();num.pop();
    int a = num.top();num.pop();
    int c = op.top();op.pop();
    int x;
    if (c == '+') x = a + b;
    else if (c == '-') x = a - b;
    else if (c == '*') x = a * b;
    else x = a / b;
    num.push(x);
}


int main()
{
    cin >> s;
    for(int i = 0; i < s.size(); i ++){
        char ch = s[i];
        //是数字,把整个数字从字符串中抠出来
        if(isdigit(ch)){
            int x = 0, j = i;
            while(isdigit(s[j]) && j < s.size()){
                x = x * 10 + s[j] - '0';
                j ++;
            }
            i = j - 1;
            num.push(x);
        }
        else if(ch == '(')op.push(ch);
        //1、括号结束
        else if(ch == ')'){
            while(op.top() != '(')eval();
            op.pop();
        }
        else{
            /*
            2、当前操作符的优先级小于等于栈内操作符的优先级
            */
            while(op.size() && op.top() != '(' && pr[ch] <= pr[op.top()] )eval();
            op.push(ch);
        }
    }
    while(op.size())eval();
    cout << num.top() << '\n';
    return 0;
}
/*
当遇到1 、 2情况,需要将前面的值计算出来
*/
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个经典的二叉问题。给出一个二叉的先序遍历和序遍历,我们可以确定这棵二叉,并输出它的后序遍历。 我们可以根据先序遍历的第一个节点确定根节点,在序遍历找到根节点,然后将序遍历分为左子和右子两部分。由于是递归定义的,我们可以递归地处理左子和右子,最终确定整棵。 具体来说,我们可以先将先序遍历和序遍历存储为两个数组,然后编写一个递归函数,输入先序遍历数组、序遍历数组、左子的开始位置和结束位置、右子的开始位置和结束位置,输出根节点,并将左子和右子分别递归处理。 下面是代码实现: ```python def buildTree(preorder, inorder): if not preorder or not inorder: return None root_val = preorder[0] root = TreeNode(root_val) index = inorder.index(root_val) root.left = buildTree(preorder[1:index+1], inorder[:index]) root.right = buildTree(preorder[index+1:], inorder[index+1:]) return root ``` 这个函数的时间复杂度是 O(n^2),其 n 是二叉的节点个数。因为我们在序遍历需要搜索根节点的位置,这个搜索的时间复杂度是 O(n)。在最坏的情况下,二叉退化成链,递归深度为 n,因此总时间复杂度是 O(n^2)。 如果我们使用哈希存储序遍历每个节点的位置,那么可以将搜索根节点的时间复杂度优化到 O(1),总时间复杂度优化到 O(n)。下面是改进后的代码实现: ```python def buildTree(preorder, inorder): index = {val: i for i, val in enumerate(inorder)} def helper(preorder, inorder, left, right): if left > right: return None root_val = preorder.pop(0) root = TreeNode(root_val) i = index[root_val] root.left = helper(preorder, inorder, left, i - 1) root.right = helper(preorder, inorder, i + 1, right) return root return helper(preorder, inorder, 0, len(inorder) - 1) ``` 这个函数的时间复杂度是 O(n),其 n 是二叉的节点个数。在函数,我们使用哈希 index 存储序遍历每个节点的位置,这个哈希的构建时间复杂度是 O(n),递归函数的总时间复杂度是 O(n)。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值