表达式二叉树

涞源chengyaogen.blog.chinaunix.net

一、定义

二叉树(binary tree)是一棵每个结点都不能有多于两个儿子的树。

二、数据结构设计

因为一个二叉树结点最多是有两个儿子,所以可以直接链接到他们。树结点的声明在结构上类似双向链表的声明。在声明中,一个结点就是由element(元素)的信息加上两个 到其他结点的引用(left和right)组成的结构

struct BinaryNode

{

Object    element;                    //The data in the node

struct BinaryNode   *left;        //Left   child

struct BinaryNode   *right;     //Right  child

};

三、表达式树

表达式树的树叶是操作数(operand),加常数或变量名字,而其他的结点为操作数(operator)。由于这里所有的操作都是二元的,因此这棵特定的树正好是二叉树,虽然这是最简单的情况,但是结点还是有可能含有多于两个的儿子,这里我们不讨论。

四、构造一棵表达式树

之前我们实现过一个中缀表达式求值的具体程序,在求值过程中需要用两个栈,并且代码并不简单。而这里你会看到,对于表达式树的求值操作却非常简单,甚至只需要两条语句。因为这里大部分操作都是递归定义,二递归函数本身都是很简洁的,甚至比你想象的还要简单,甚至只需要两条语句。因为这里大部分操作都是递归定义,二递归函数本身都是很简洁的,甚至比你想象的还要简单!就像树的遍历操作。三种遍历分别是先序遍历、中序遍历与后序遍历,正好对应表达式的三种形式:前缀型、中缀型与后缀型。其中为大家熟知的是中缀形式,如2+3*(5-4)。前缀型表达式又叫波兰式(Polish Notation),后缀性表达式又叫逆波兰式(Reverse Polish Notation)。他们最早于1920年波兰数学家Jan Lukasiewicz发明,这两种表示方式的最大特点是不需要括号来表明优先级,他们经常用于计算机科学,特别是编译器设计方面。

下面给出一种算法来把后缀表达式转变成表达式树。我们一次一个符号地读入表达式。如果符号是操作数,那么就建立一个单结点树并将它推入栈中。如果符号是操作符,那么就从栈中弹出两棵树T1和T2(T1先弹出)并形成一棵新的树,该树的根就是操作符,它的左、右儿子分别是T2和T1。然后将指向这颗树的指针压入栈中。

下面来看一个例子。设输入为ab+cde+**

前两个符号是操作数,因此创建两棵单结点树并将指向它们的指针压入栈中。

接着,"+"被读入,因此指向两棵树的指针被弹出,形成一棵新的树,并将指向它的指针压入栈中。

然后,c,d和e被读入,在单个结点树创建后,指向对应的树的指针被压入栈中。

接下来读入"+"号,因此两棵树合并。

继续进行,读入"*"号,因此,弹出两棵树的指针合并形成一棵新的树,"*"号是它的根。

最后,读入一个符号,两棵树合并,而指向最后的树的指针被留在栈中。

下面我们来实现以下它吧

#include <stdio.h>
#include <stdlib.h>

#define MAX 100

//树结点的设计
typedef struct node
{
    //数字和运算符
    union
    {
        char operator;
        int data;
    };

    struct node *lchild;
    struct node *rchild;    

}TreeNode;

//树栈的设计
typedef struct
{
    TreeNode *buf[MAX];
    int n;

}TreeStack;

//创建空栈
TreeStack *create_empty_stack()
{
    TreeStack *pstack;

    pstack = (TreeStack *)malloc(sizeof(TreeStack));
    pstack->n = -1;

    return pstack;
}

//入栈
int push_stack(TreeStack *p,TreeNode *data)
{
    p->n ++;
    p->buf[p->n] = data;

    return 0;
}

//出栈
TreeNode *pop_stack(TreeStack *p)
{
    TreeNode *data;

    data = p->buf[p->n];
    p->n --;

    return data;
}

//判断空栈
int is_empty_stack(TreeStack *p)
{
    if(p->n == -1)
    {
        return 1;

    }else{
        return 0;
    }
}

//后缀表达式树的创建
TreeNode *create_express_tree(char *str,TreeStack *p)
{
    int i = 0;
    TreeNode *current;
    TreeNode *left,*right;

    while(str[i])
    {
        if(str[i] == ‘ ‘)
        {
            i ++;
            continue;
        }

        if(str[i] >= ‘0‘ && str[i] <= ‘9‘)
        {
            current = (TreeNode *)malloc(sizeof(TreeNode));
            current->data = str[i] - ‘0‘;
            current->lchild = current->rchild = NULL;
            push_stack(p,current);

        }else{
            current = (TreeNode *)malloc(sizeof(TreeNode));
            current->operator = str[i];
            right = pop_stack(p);
            left = pop_stack(p);
            current->lchild = left;
            current->rchild = right;
            push_stack(p,current);
        }

        i ++;
    }

    return p->buf[p->n];
}

//打印结点
void print_node(TreeNode *p)
{
    if(p->lchild == NULL && p->rchild == NULL)
    {
        printf("%d ",p->data);

    }else{

        printf("%c ",p->operator);
    }

    return;
}

//访问结点
int vist_node(TreeNode *p)
{
    print_node(p);

    return 0;
}

//树的后序遍历
int PostOrder(TreeNode *p)
{
    if(p != NULL)
    {
        PostOrder(p->lchild);//左
        PostOrder(p->rchild);//右
        vist_node(p);//根
    }

    return 0;
}

//树的中序遍历
int InOrder(TreeNode *p)
{
    if(p != NULL)
    {
        InOrder(p->lchild);//左
        vist_node(p);//根
        InOrder(p->rchild);//右
    }

    return 0;
}

//树的前序遍历
int PreOrder(TreeNode *p)
{
    if(p != NULL)
    {
        vist_node(p);//根
        PreOrder(p->lchild);//左
        PreOrder(p->rchild);//右
    }

    return 0;
}

/队列的设计
struct _node_
{
    TreeNode *data;
    struct _node_ *next;
};

typedef struct
{
    struct _node_ *front;
    struct _node_ *rear;

}Queue;

//创建空队列
Queue *create_empty_queue()
{
    struct _node_ *pnode;
    Queue *qhead;

    qhead = (Queue *)malloc(sizeof(Queue));
    pnode = (struct _node_ *)malloc(sizeof(struct _node_));
    pnode->next = NULL;

    qhead->front = qhead->rear = pnode;

    return qhead;
}

//入队
int EnterQueue(Queue *qhead,TreeNode *data)
{
    struct _node_ *temp;

    temp = (struct _node_ *)malloc(sizeof(struct _node_ *));
    temp->data = data;
    temp->next = NULL;

    qhead->rear->next = temp;
    qhead->rear = temp;

    return 0;
}

//出队
TreeNode *DeleteQueue(Queue *qhead)
{
    struct _node_ *temp;

    temp = qhead->front;
    qhead->front = temp->next;
    free(temp);
    temp = NULL;

    return qhead->front->data;
}

//队列为空
int is_empty_queue(Queue *qhead)
{
    if(qhead->front == qhead->rear)
        return 1;
    else
        return 0;
}

//树的层次遍历
int NoOrder(TreeNode *p)
{
    Queue *qhead;
    TreeNode *pdata;

    qhead = create_empty_queue();
    EnterQueue(qhead, p);

    while(!is_empty_queue(qhead))
    {
        pdata = DeleteQueue(qhead);
        vist_node(pdata);

        if(pdata->lchild)EnterQueue(qhead,pdata->lchild);
        if(pdata->rchild)EnterQueue(qhead,pdata->rchild);
    }

    return 0;
}

int main()
{
    TreeNode *thead;
    TreeStack *pstack;
    int i = 0;
    char buf[100];

    while((buf[i++] = getchar()) != ‘\n‘ && i < 100);
    buf[i-1] = 0;

    pstack = create_empty_stack();
    thead = create_express_tree(buf,pstack);

    printf("PostOrder:: ");
    PostOrder(thead);
    printf("\n");

    printf("InOrder:: ");
    InOrder(thead);
    printf("\n");

    printf("PreOrder:: ");
    PreOrder(thead);
    printf("\n");

    printf("NoOrder::");
    NoOrder(thead);
    printf("\n");

    return 0;
}

  

运行结果:

时间: 2024-10-10 09:48:55

表达式二叉树的相关文章

表达式求值(二叉树方法/C++语言描述)(二)

表达式二叉树节点的数据可能是运算数或运算符,可以使用一个联合体进行存储:同时还需要一个变量来指示存储的是运算数还是运算符,可以采用和栈方法中一样的枚举类型TokenType: 1 typedef enum 2 { 3 BEGIN, 4 NUMBER, 5 OPERATOR, 6 LEFT_BRAC, 7 RIGHT_BRAC 8 } TokenType; 9 10 class Token 11 { 12 public: 13 TokenType _type; 14 union 15 { 16 c

触手不及(巴科斯范式求表达式树)

本题为学军神犇 cxt 出的神题. 题意 为了避免流露出自己的感情伤害别人, 小 M.M.T. 决定通过一个表达式来传递心意. 给出一个等式. 等式左边是一个 \(int\) 范围内的数, 等式右边是一个合法的 c++ 表达式. 例如:\(233 = 66 ? 4 ? 31\) 保证等式右边只包含数字 \(x (x ∈ [0, p),p\) 是给定的质数\()\), 加号, 减号, 乘号, 除号, 左右括号. 保证等式中没有任何空格,tab 等不可见字符. 而且保证合法. 但是遗憾的是, 因为一

poj 北京大学 2014研究生推免上机考试(校内)

考试完后过了这么久,来发福利了攒人品了~~~ 大家可以在poj地址http://bailian.openjudge.cn/tm201401/找到所有试题,并可以在百练中搜索相应试题自己练习. A:单词排序 总时间限制: 1000ms 内存限制: 65536kB 描述 输入一行单词序列,相邻单词之间由1个或多个空格间隔,请按照字母顺序输出这些单词(即按照字符串中字母的ASCII码排序,区分大小写,当首字母相同时,比较第2个字母,依次类推),要求重复的单词只输出一次. 输入 一行单词序列,最少1个单

第四次作业 树

1.2 树结构学习体会 难,不是我等凡夫俗子可以学会的. 困难点:对递归的理解不够透彻,一直转不过来. 解决办法:多看点代码. 2.PTA实验作业 题目一:6-4 jmu-ds-表达式树(25 分) 题目: 输入一行中缀表达式,转换一颗二叉表达式树,并求解. 表达式只包含+,-,*,/,(,)运算符,操作数只有一位,且为整数(有兴趣同学可以考虑负数小数,两位数做法).按照先括号,再乘除,后加减的规则构造二叉树. 如图所示是"1+(2+3)*2-4/5"代数表达式对应二叉树,用对应的二叉

小学生四则运算之做到晚上不用睡觉版(python实现)

1. Github地址及项目成员 https://github.com/zhengjinhuai/arithmetic-generators(进怀github) https://github.com/jezing/arithmetic-generators(曾霖github) 郑进怀 3117004637 :曾霖 3117004602 2. PSP表格: PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning 计划 2

C# - 二叉树表达式计算

很早以前就写过双栈的表达式计算. 这次因为想深入学一下二叉树,网上都是些老掉牙的关于二叉树的基本操作. 感觉如果就学那些概念,没意思也不好记忆.于是动手写了一个表达式计算的应用例子. 这样学习印象才深嘛. 我喜欢逆过来贴代码~ 这是运行结果: cal() 是节点类里的计算方法,从根节点调用,递归所有子节点进行计算.Left,Right分别是左右子节点. 1 public double cal() 2 { 3 if (this.isDig==false) 4 { 5 return CAL(Fuha

二叉树的三种遍历的应用(表达式,求深度,叶子数,结点数,二叉树的建立,复制)

表达式的表示 如图所示的二叉树表达式: a+b*(c-d)-e/f 若先序遍历此二叉树,按访问结点的先后次序将结点排列起来,其先序序列为: (波兰式,前缀表达式)  -+a*b-cd/ef 按中序遍历,其中序序列为:a+b*c-d-e/f (中缀表达式) 按后序遍历,其后序序列为:abcd-*+ef/- (逆波兰式,后缀表达式) 注:人喜欢中缀形式的算术表达式,对于计算机,使用后缀易于求值 查询二叉树中某个结点 使用先序遍历算法进行查询遍历 // 若二叉树中存在和 x 相同的元素,则 p 指向该

二叉树和栈构建的表达式树

这是另外另一个根据后缀表达式进行翻译的实现方法,主要利用栈和二叉树 利用的自定义头文件如下 1.二叉树基本定义 btree.h 1 #ifndef _btree_h_ 2 #define _btree_h_ 3 4 #include "iostream" 5 #include "stdlib.h" 6 7 typedef struct _btree_ 8 { 9 char data; 10 struct _btree_ *leftTree; 11 struct _b

表达式求值(二叉树方法/C++语言描述)(五)

本例中的二叉树图是使用Graphviz绘制的(Graphviz官网),在Ubuntu Linux下可以使用apt-get命令安装它: 1 sudo apt-get install graphviz 表达式"1+2*3"和"1*2+3"的Dot代码如下: 1 # exp1_3.dot 2 digraph G{ 3 1 4 2 5 3 6 "*" -> 2 7 "*" -> 3 8 "+" ->