【数据结构知识】【栈】【树】波兰序列和逆波兰序列【详细版】

波兰序列和逆波兰序列

目录

波兰序列和逆波兰序列

1、栈

中缀表达式——>后缀表达式

 中缀表达式——>前缀表达式

 2、树


例如表达式:8+(3-1)*5

则:建立二叉树,根节点都是运算符,叶子节点都是操作数。

前序遍历:波兰序列(前缀表达式)

中序遍历:原始表达式(中缀表达式)

后序遍历:逆波兰序列(后缀表达式)

整个过程既可以由栈来实现,也可以由二叉树来实现,下面分别来实现两种方法。

1、栈

中缀表达式——>后缀表达式

从前往后遍历:

  • 若为操作数,则直接输出
  • 若为(,则直接压栈
  • 若为),则弹出栈顶元素,直到遇到(
  • 其他运算符,栈为空、栈顶为(、栈顶优先级低,则直接压栈;否则先弹出栈顶元素,再压入新元素
#include<iostream>
#include<algorithm>
#include<stack>

using namespace std;

//数组的横纵顺序:+ - * /
//x<y则为1,否则为0
int cmp[4][4]={{0,0,1,1},{0,0,1,1},{0,0,0,0},{0,0,0,0}};

//若top优先级低于c,则返回1,否则返回0
int compare(char top,char c){
    int x,y;
    if(top=='+') x=0;
    else if(top=='-') x=1;
    else if(top=='*') x=2;
    else x=3;
    
    if(c=='+') y=0;
    else if(c=='-') y=1;
    else if(c=='*') y=2;
    else y=3;
    
    return cmp[x][y];
}

int main(){
    string s;
    cin>>s;
    cout<<"中缀表达式:"<<s<<endl;
    
    stack<char> stk;
    string res; //输出的结果
    for(auto c:s){
        
        if(c>='0'&&c<='9') res+=c;  //1.若为操作数,则直接输出
        else if(c=='(') stk.push(c);//2.若为(,则直接压栈
        else if(c==')'){            //3.若为),则弹出栈顶元素,直到遇到(
            while(stk.size()&&stk.top()!='('){//弹出栈顶元素,直到遇到(
                res+=stk.top();
                stk.pop();
            }
            stk.pop();  //弹出左括号
        }
        else{                      //4.其他运算符,栈为空/栈顶为(/栈顶优先级低,则直接压栈
            if(stk.empty()) stk.push(c);//栈为空
            else{
                if(stk.top()=='(') stk.push(c);//若栈顶是(,则直接压栈
                else if(compare(stk.top(),c)) stk.push(c);//栈顶优先级低
                else {                                      //栈顶优先级不低,则先弹出栈顶元素,再压入新元素
                    while(stk.size()&&stk.top()!='('&&!compare(stk.top(),c)){
                        res+=stk.top();
                        stk.pop();
                    }
                    stk.push(c);//压入新元素
                }
            }
            
        }
    }
    while(stk.size()){//若栈还非空,弹出栈元素
        res+=stk.top();
        stk.pop();
    }
    cout<<"后缀表达式:"<<res<<endl;

    return 0;
}

 中缀表达式——>前缀表达式

从后往前遍历:

  • 若为数值,则直接输出
  • 若为),则压入栈中
  • 若为(,则弹出栈顶元素,直到遇到)
  • 其他运算符,若栈为空、栈顶为)、比栈顶元素优先级高或相等,则直接压栈,否则弹出元素,再压入新元素
  • 反转最后结果
#include<iostream>
#include<algorithm>
#include<stack>

using namespace std;

//数组的横纵顺序:+ - * /
//x>y则为0,否则为1
int cmp2[4][4]={{1,1,1,1},{1,1,1,1},{0,0,1,1},{0,0,1,1}};

//若top优先级高,则不能压栈
int compare2(char top,char c){
    int x,y;
    if(top=='+') x=0;
    else if(top=='-') x=1;
    else if(top=='*') x=2;
    else x=3;
    
    if(c=='+') y=0;
    else if(c=='-') y=1;
    else if(c=='*') y=2;
    else y=3;
    
    return cmp2[x][y];
}

int main(){
    string s;
    cin>>s;
    cout<<"中缀表达式:"<<s<<endl;
    
/*********************************前缀表达式*************************************/
    string res2; //存放输出结果
    stack<char> stk2;
    for(int i=s.size()-1;i>=0;i--){//从后往前遍历
        if(s[i]>='0'&&s[i]<='9') res2+=s[i]; //1.若为数值,则直接输出
        else if(s[i]==')') stk2.push(s[i]);  //2.若为),则压入栈中
        else if(s[i]=='(') {                //3.若为(,则弹出栈顶元素,直到遇到)
            while(stk2.top()!=')'){
                res2+=stk2.top();
                stk2.pop();
            }
            stk2.pop(); //弹出右括号
        }
        else{                           //4.其他运算符,若栈为空、栈顶为)、比栈顶元素优先级高或相等,则直接压栈
            if(stk2.empty()) stk2.push(s[i]); //栈为空
            else if(stk2.top()==')') stk2.push(s[i]); //栈顶为)
            else{
                if(compare2(stk2.top(),s[i])) stk2.push(s[i]); //比栈顶元素优先级高或相等
                else{
                    while(stk2.size()&&stk2.top()!=')'&&!compare2(stk2.top(),s[i])){//栈顶元素优先级高,弹出元素
                        res2+=stk2.top();
                        stk2.pop();
                    }
                    stk2.push(s[i]);//压入新元素
                }
            }
        }
    }
    while(stk2.size()) { //若栈非空,弹出元素
        res2+=stk2.top();
        stk2.pop();
    }
    
    reverse(res2.begin(),res2.end()); //反转最后结果
    cout<<"前缀表达式:"<<res2<<endl;
    
    return 0;
}

 2、树

递归建立树

#include<iostream>
#include<algorithm>

using namespace std;

//二叉树节点结构
struct TreeNode{
  
    char val;
    TreeNode* left;
    TreeNode* right;
    
    TreeNode(char x):val(x),left(NULL),right(NULL){
        
    }
};

const int N=4;

//x>=y——>1
int cmp[N][N]={
   //+ - * /
    {1,1,0,0},//+
    {1,1,0,0},//-
    {1,1,1,1},//*
    {1,1,1,1}};///

//运算符集合
char op[N]={'+','-','*','/'};

//若a>=b返回1(这里>=指优先级)
int compare(char a,char b){
    int x,y;
    for(int i=0;i<N;i++){
        if(a==op[i]) x=i;
        if(b==op[i]) y=i;
    }
    return cmp[x][y];
}

//判断c是否是运算符
bool check(char c){
    for(int i=0;i<N;i++)
        if(c==op[i]) return true;
    return false;
}

//在s的[left,right]区间内找到优先级最低的下标返回
int find(const string &s,int left,int right){
    char minc='*';
    int res=-1;
    int bracket;
    for(int i=left;i<=right;i++){
        bracket=0;
        if(s[i]=='('){//遇到括号,把(...)看成一个:(一个运算数)
            bracket++;
            while(bracket){
                i++;
                if(s[i]=='(') bracket++;
                else if(s[i]==')') bracket--;
            }
            continue; //作用于外for循环
        }

        if(check(s[i])&&compare(minc,s[i])){
            res=i;
            minc=s[i];
        }
    }
    return res;
}
//...w...  w是优先级最低的下标,为当前根节点,继续递归处理w左半边和w右半边,分别为左子树和右子树
TreeNode* createTree(const string &s,int left,int right){
    auto root=new TreeNode(-1);
    
    if(left>=right){
        root->val=s[left];
        return root;
    }
    
    int bracket=0;//括号标记判断
    if(s[left]=='('&&s[right]==')'){
        bracket++;
        int j=left;
        while(bracket){//若是(...)则处理,若是(.).(.)则不处理
            j++;
            if(s[j]=='(') bracket++;
            else if(s[j]==')') bracket--;
        }
        if(j==right) {//剥下最外层括号(...)——>...
            left++;
            right--;
        }
    }
    
    int w=find(s,left,right);
    root->val=s[w];
    root->left=createTree(s,left,w-1);
    root->right=createTree(s,w+1,right);
    
    return root;
}

//先序遍历:前缀表达式
void preOrder(TreeNode* root){
    if(root){
        cout<<root->val<<" ";
        preOrder(root->left);
        preOrder(root->right);
    }
}

//中序遍历:中缀表达式
void inOrder(TreeNode* root){
    if(root){
        inOrder(root->left);
        cout<<root->val<<" ";
        inOrder(root->right);
    }
}

//后序遍历:后缀表达式
void postOrder(TreeNode* root){
    if(root){
        postOrder(root->left);
        postOrder(root->right);
        cout<<root->val<<" ";
    }
}

int main(){
    string s;
    cin>>s;
    auto root=createTree(s,0,s.size()-1);
    cout<<"前缀表达式:";
    preOrder(root);
    cout<<endl;
    cout<<"中缀表达式:";
    inOrder(root);
    cout<<endl;
    cout<<"后缀表达式:";
    postOrder(root);
    cout<<endl;
    return 0;
}

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

烊萌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值