zoukankan      html  css  js  c++  java
  • 用二叉树表示表达式

      

    先看中缀表达式的二叉树表示:

        

    /*
    * 中缀表达式 构建 二叉树
    *
    * 方法: 每次找到“最后计算”的运算符,作为当前树的根,然后递归处理
    * 详见 刘汝佳《算法竞赛入门经典》 P198
    *
    */
    #include <iostream>
    using namespace std;

    const int maxn = 1000;

    //每个节点的左右儿子编号
    int lch[maxn], rch[maxn];
    //节点的字符
    char op[maxn];
    //节点数
    int cnt = 0;

    //s的[x, y)作为范围
    int buildTree(char *s, int x, int y){
    //c1, c2分别记录出现在括号外的最右边的加减号和乘除号
    int c1 = -1, c2 = -1, p = 0, u;

    //当前表达式长度为1,则直接以此为一棵树
    if(y - x == 1){
    u = cnt++; //第u个节点
    lch[u] = rch[u] = -1;
    op[u] = s[x];
    return u;
    }

    //p==0表示在括号外
    for(int i=x; i<y; i++){
    switch(s[i]){
    case '(': p++; break;
    case ')': p--; break;
    case '+': case '-':
    if(p == 0) c1 = i; //p==0说明s[i]不在括号内
    break;
    case '*': case '/':
    if(p == 0) c2 = i;
    break;
    }
    }

    if(c1 < 0) c1 = c2; //括号外没有 + 或 - ,则选括号外的 * 或 /
    if(c1 < 0) return buildTree(s, x+1, y-1); //括号外也没有* 或 /, 说明表达式被一个括号括住,去括号

    u = cnt++;
    lch[u] = buildTree(s, x, c1);
    rch[u] = buildTree(s, c1+1, y);
    op[u] = s[c1];

    return u;
    }


    int main(){




    return 0;
    }

    下面是转的:

    包括中缀、后缀、前缀用二叉树表示:

        

    2. 需求分析:

    1)功能:表达式可以用二叉树表示,对于简单的四则运算,请实现以下功能

       1】对于任意给出的前缀表达式(不带括号)、中缀表达式(可以带括号)或后缀表达式(不带括号),能够在计算机内部构造出一棵表达式二叉树,并且图示出来(图形的形式)。

       2】对于构造好的内部表达式二叉树,按照用户的要求输出相应的前缀表达式(不带括号)、中缀表达式(可以带括号,但不允许冗余括)或后缀表达式(不带括号)。

    提示:所谓中缀表达式中的冗余括号,就是去掉括号后不影响表达式的计算顺序。例如:“(c+b+a”中的括号是冗余的,可以表示成不冗余的“c+b+a”。

    2)输入输出要求:请输入字符串表达式:

                                      树形二叉树(图形显示)

                                      中缀表达式为:

    前缀表达式为:

    后缀表达式为:

    3.   概要设计:(算法)

    分成两部分完成:

    1】前缀、中缀、后缀表达式->二叉树表达式

    前缀表达式->二叉树表达式:(a)碰到操作数则把其值赋给相应的新申请的二叉树结点,地址压栈;(b)碰到操作符则把其值赋给相应的新申请的二叉树,并从栈中弹出两个地址,分别作为其右指针和左指针,然后再把其地址压栈,最后一个地址即为二叉树的根结点地址。

    中缀表达式->二叉树表达式:把中缀表达式转换成后缀表达式,然后再建立二叉树。

    后缀表达式->二叉树表达式:(a)碰到操作数则把其值赋给相应的新申请的二叉树结点,压栈;(b)碰到操作符则把其值赋给相应的新申请的二叉树结点,取栈顶元素,取栈顶元素分别作为右、左节点。开始时用变量root保存。

    1】二叉树表达式->前缀、中缀、后缀表达式

    二叉树表达式->前缀表达式:对二叉树表达式进行前序遍历。

    二叉树表达式->中缀表达式:对二叉树表达式进行中序遍历,若结点操作符的优先级高于其左或右子树,在打印相应的子树之前先打印开括号,在打印相应的子树最后在打印一个闭括号。

    二叉树表达式->后缀表达式:对二叉树表达式进行后序遍历。

    建立表达式树就是建立树中的每一个结点,将每一个结点链接起来就是整棵树。而在建立深度低的结点时要将其左右指针指向之前建立的深度比它高一级的结点(’*’要指向’2’’3’,而’+’又要指向’*’)。这样我们可以用栈来存放每次建立的结点,按照优先级(表达式为中缀型)或顺序扫描表达式(表达式为波兰式与逆波兰式)建立每一个结点。建立结点的顺序即为表达式求值的顺序。如果扫描到操作数则直接新建一个左右指针为空的结点,并压入结点栈中(存放结点指针)。遇到运算符时首先新建一个结点,然后从栈中依次弹出两个结点,并让新建立的结点的左右指针域指向它们。当所有结点建立完毕时,如果表达式没有错误(这里假设输入表达式正确),这时栈中应该只剩下一个结点,它就是所建立的表达式的根结点。


    4. 详细设计:(具体方法)

    首先创建一个节点类TNode:包含操作符oper、左孩子left、右孩子rightisOper()判断是否为操作符,getOperOrder()返回运算符op所对应的优先级,freeTree()程序结束销毁二叉树,postOrder()先序遍历,preOrder()后序遍历,inOrder()中序遍历,ExpTree1()后缀表达式生成二叉树,ExpTree3()前缀表达式生成二叉树,ExpTree2()中后缀表达式生成二叉树,count()求值函数,paint()输出函数


    附代码:

        

    #include <iostream>
    #include <stack>
    #include <queue>
    #include <string>
    #include<math.h>
    using namespace std;
    class TNode//节点类
    { public:
    char oper;
    TNode *left;
    TNode *right;
    int s; int t;
    TNode()
    { left=right=NULL;
    oper=0;
    }
    TNode(char op)
    { left=right=NULL;
    oper=op;}};
    bool isOper(char op)//判断是否为运算符
    {
    char oper[]={'(',')','+','-','*','/','^'};
    for(int i=0;i<sizeof(oper);i++)
    { if(op==oper[i])
    {
    return true;
    } }
    return false;}

    int getOperOrder(char op)//返回运算符op所对应的优先级
    { switch(op)
    { case '(':
    return 1;
    case '+':
    case '-':
    return 2;
    case '*':
    case '/':
    return 3;
    case '^':
    return 4;
    default:
    //定义在栈中的右括号和栈底字符的优先级最低
    return 0;
    } }
    void freeTree(TNode *&p) //释放树
    { if(p->left!=NULL)
    freeTree(p->left);
    if(p->right!=NULL)
    freeTree(p->right);
    delete(p);
    cout<<"Memory free "; }

    void postOrder(TNode *p) //先序遍历
    { if(p)
    { postOrder(p->left);
    postOrder(p->right);
    cout<<p->oper;
    } }

    void preOrder(TNode *p) //后序遍历
    { if(p)
    { cout<<p->oper;
    preOrder(p->left);
    preOrder(p->right);
    } }

    void inOrder(TNode *p)//中序遍历
    { if(p)
    { if(p->left)
    { if(isOper(p->left->oper)
    && getOperOrder(p->left->oper)
    <getOperOrder(p->oper))
    { cout<<"(";
    inOrder(p->left);
    cout<<")";
    }else{
    inOrder(p->left);
    } }
    cout<<p->oper;
    if(p->right)
    { if(isOper(p->right->oper)
    && getOperOrder(p->right->oper)
    <=getOperOrder(p->oper))
    { cout<<"(";
    inOrder(p->right);
    cout<<")";
    }else{
    inOrder(p->right);
    } } } }

    void ExpTree1(TNode *&p,string str)//后缀表达式生成二叉树
    {stack <TNode*> nodeStack;
    char temp;
    int i=0;
    temp=str[i++];
    while(temp!='\0')
    { if(temp!='\0'&&!isOper(temp))//不是运算符,则进栈
    { p=new TNode(temp);//以temp为结点值构造二叉树结点
    nodeStack.push(p);
    temp=str[i++];}
    else
    { p=new TNode(temp);
    if(nodeStack.size())
    { p->right=nodeStack.top();//若非空则弹栈并设为结点的右孩子
    nodeStack.pop(); }
    if(nodeStack.size())
    { p->left=nodeStack.top();//若非空则弹栈并设为结点的左孩子
    nodeStack.pop(); }
    nodeStack.push(p);
    temp=str[i++];
    } } }
    void ExpTree3(TNode *&p, string str)//前缀表达式生成二叉树
    { stack <TNode*> nodeStack;
    char temp;
    int i=str.size()-1;
    temp=str[i--];
    while(temp!='\0')
    { if(temp!='\0'&&!isOper(temp))
    { p=new TNode(temp);//以temp为内容来建立新的结点
    nodeStack.push(p);
    temp=str[i--];}
    else
    { p=new TNode(temp);
    if(nodeStack.size())//若栈顶指针所指结点左孩子为空
    { p->left=nodeStack.top(); //则当前结点设置成其左孩子
    nodeStack.pop();
    } if(nodeStack.size())//若栈顶指针所指结点右孩子为空
    { p->right=nodeStack.top();//则当前结点设置成其右孩子
    nodeStack.pop();//栈顶元素左右孩子指针设置完毕弹出 }
    nodeStack.push(p);
    temp=str[i--];
    } } }

    void ExpTree2(TNode *&p, string str)//中缀表达式转换成后缀表达式生成二叉树
    { stack<char> a;
    char temp;
    string Postfixexp="";
    int i=0;
    temp=str[i++];
    while(temp!='\0')
    { if(!isOper(temp))
    { Postfixexp+=temp;
    temp=str[i++];}
    else if(temp=='(')//进栈
    { a.push(temp);
    temp=str[i++];}
    else if(temp==')'){
    while(a.top()!='(')//脱括号
    { Postfixexp+=a.top();
    a.pop();//在碰到开括号和栈为空前反复弹出栈中元素 }
    a.pop();
    temp=str[i++];
    }else if(temp=='+'||temp=='-'||temp=='*'||temp=='/')//出栈{
    while(!a.empty()&&a.top()!='('&&getOperOrder(a.top())>=getOperOrder(temp))//若栈非空栈顶不是左括号且栈顶元素优先级不低于输入运算符时,
    //将栈顶元素弹出到后缀表达式中,并且str下标加1
    { Postfixexp+=a.top();
    a.pop(); }
    a.push(temp);
    temp=str[i++];
    } }
    while(!a.empty())
    { Postfixexp+=a.top();
    a.pop();
    }
    ExpTree1(p,Postfixexp); }
    void count(TNode *p,int &height,int n)//求值函数
    { if(p->left==NULL&&p->right==NULL)
    { if(n>height)
    height=n;}
    if(p->left!=NULL)
    count(p->left,height,n+1);
    if(p->right!=NULL)
    count(p->right,height,n+1); }
    void paint(TNode *p)//输出函数
    { int height=0;
    int h=0;
    int i;
    using std::queue;
    queue<TNode*> aQueue;
    count(p,height,1);
    TNode *pointer=p;
    TNode *lastpointer;
    if(pointer)
    { pointer->s=1;
    pointer->t=1;
    aQueue.push(pointer); }
    while(!aQueue.empty())
    { lastpointer=pointer;
    pointer=aQueue.front();
    aQueue.pop();
    if(pointer->s>h)
    {cout<<endl;
    h=pointer->s;}
    if(pointer->t==1)
    {for(i=0;i<pow(2,height-pointer->s)-1;i++)
    cout<<" ";}
    else if(lastpointer->s!=pointer->s){
    for(i=0;i<(pointer->t-1)*(pow(2,height-pointer->s+1)-1)+(pointer->t-1)-1+pow(2,height-pointer->s);i++)
    cout<<" "; }
    else
    { for(i=0;i<(pointer->t-lastpointer->t)*(pow(2,height-pointer->s+1)-1)+(pointer->t-lastpointer->t)-1;i++)
    cout<<" "; }
    cout<<pointer->oper;
    if(pointer->left!=NULL){
    pointer->left->s=pointer->s+1;
    pointer->left->t=pointer->t*2-1;
    aQueue.push(pointer->left);}
    if(pointer->right!=NULL){
    pointer->right->s=pointer->s+1;
    pointer->right->t=pointer->t*2;
    aQueue.push(pointer->right);
    } } }
    int main()
    { string expression;
    TNode *tree;
    cout<<endl<<"请输入字符串表达式:";
    cin>>expression;
    if(isOper(expression[0]))
    ExpTree3(tree,expression);
    else if(isOper(expression[1]))
    ExpTree2(tree,expression);
    else
    ExpTree1(tree,expression);
    paint(tree);
    cout<<endl;
    cout<<"中缀表达式为:";
    inOrder(tree);
    cout<<endl;
    cout<<"前缀表达式为:";
    preOrder(tree);
    cout<<endl;
    cout<<"后缀表达式为:";
    postOrder(tree);
    cout<<endl;
    freeTree(tree);
    cout<<endl;
    system("pause");
    return 0; }






  • 相关阅读:
    VSCode 配置 Python 开发环境
    出现:Microsoft Visual C++ 14.0 is required 的解决方案
    python3 pathlib库中的Path类的使用
    使用 AI 绘制箭头
    Adobe Illustrator 入门 新建 保存图片
    jinja2
    Java 读取和写入文本文件
    Affy包 estrogen包
    GEOquery
    apply() 函数家族介绍
  • 原文地址:https://www.cnblogs.com/longdouhzt/p/2204856.html
Copyright © 2011-2022 走看看