二叉树,波兰式,逆波兰式,二叉树的遍历

原博地址:http://lib.csdn.net/article/datastructure/15516

转载供以后研究

中缀表达式与后缀表达式

中缀表达式 (或中缀记法)是一个通用的算术或逻辑公式表示方法,  操作符 是以中缀形式处于 操作数 的中间(例:3 + 4),中缀表达式是人们常用的算术表示方法。
前缀表达式 (例:+ 3 4)或 后缀表达式 (例:3 4 +)相比,中缀表达式不容易被计算机解析,但仍被许多程序语言使用,因为它符合人们的普遍用法。
与前缀或后缀记法不同的是,中缀记法 中括号 是必需的。计算过程中必须用括号将操作符和对应的操作数括起来,用于指示运算的次序。
例:
(1)8+4-6*2用后缀表达式表示为:
62*84+-
(2)2*(3+5)-4+7/1用 后缀表达式 表示为:
35+2*71/4-+

 中缀表达式转为后缀表达式(又称逆波兰表达式)的方法

逆波兰算法-栈实现

将一个普通的中序 表达式 转换为 逆波兰表达式 的一般算法是:
首先需要分配2个栈,一个作为临时存储运算符的栈S1(含一个结束符号),一个作为输入逆 波兰 式的栈S2(空栈),S1栈可先放入优先级最低的运算符#,注意,中缀式应以此最低优先级的运算符结束。可指定其他字符,不一定非#不可。从中缀式的左端开始取字符,逐序进行如下步骤:
(1)若取出的字符是 操作数 ,则分析出完整的运算数,该操作数直接送入S2栈
(2)若取出的字符是 运算符 ,则将该运算符与S1栈栈顶元素比较,如果该 运算符优先级 大于S1栈栈顶 运算符 优先级,则将该运算符进S1栈,否则,将S1栈的栈顶运算符弹出,送入S2栈中,直至S1栈栈顶运算符低于(不包括等于)该运算符优先级,则将该运算符送入S1栈。
(3)若取出的字符是“(”,则直接送入S1栈底。
(4)若取出的字符是“)”,则将距离S1栈栈底最近的“(”之间的运算符,逐个 出栈 ,依次送入S2栈,此时抛弃“(”。
(5)重复上面的1~4步,直至处理完所有的输入字符
(6)若取出的字符是“#”,则将S1栈内所有运算符(不包括“#”),逐个 出栈 ,依次送入S2栈。
完成以上步骤,S2栈便为逆 波兰 式输出结果。不过S2应做一下逆序处理。便可以按照逆 波兰 式的计算方法计算了!

//#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<stack>
#include<math.h>
#include<string.h>
#definemax100
usingnamespacestd;
charex[max];/*存储后缀表达式*/
 
void trans()
{/*将算术表达式转化为后缀表达式*/
    charstr[max];/*存储原算术表达式*/
    charstack[max];/*作为栈使用*/
    charch;
    intsum,i,j,t,top=0;
    printf("*****************************************\n");
    printf("*输入一个求值的表达式,以#结束。*\n");
    printf("******************************************\n");
    printf("算数表达式:");
    i=0;/*获取用户输入的表达式*/
    do{
        i++;
        //cin>>str[i];/*此步我用的是C++C语言的话在后面之所以用这个有一点区别都*/
        scanf("%c",&str[i]);
    }while(str[i]!='#'&&i!=max);
    sum=i;
    t=1;i=1;
    ch=str[i];i++;
    //
    while(ch!='#')
    {
        switch(ch)
        {
        case'(':/*判定为左括号*/
            top++;stack[top]=ch;
            break;
        case')':/*判定为右括号*/
            while(stack[top]!='(')
            {
                ex[t]=stack[top];top--;t++;
            }
            top--;
            break;
        case'+':/*判定为加减号*/
        case'-':
            while(top!=0&&stack[top]!='(')
            {
                ex[t]=stack[top];
                top--;
                t++;
            }
            top++;
            stack[top]=ch;
            break;
        case'*':/*判定为乘除号*/
        case'/':
            while(stack[top]=='*'||stack[top]=='/')
            {
                ex[t]=stack[top];
                top--;
                t++;
            }
            top++;
            stack[top]=ch;
            break;
        case'':break;
        default:
            while(ch>='0'&&ch<='9')
            {/*判定为数字*/
                ex[t]=ch;t++;
                ch=str[i];i++;
            }
            i--;
            ex[t]='';t++;
            }
            ch=str[i];i++;
    }
    while(top!=0)
    {
        ex[t]=stack[top];
        t++;top--;
    }
    ex[t]='';
    printf("\n\t原来表达式:");
    for(j=1;j<sum;j++)
    printf("%c",str[j]);
    printf("\n\t逆波兰式:",ex);
    for(j=1;j<t;j++)
    printf("%c",ex[j]);
}
 
void compvalue()
{/*计算后缀表达式的值*/
    floatstack[max],d;/*作为栈使用*/
    charch;
    intt=1,top=0;/*t为ex下标,top为stack下标*/
    ch=ex[t];t++;
    while(ch!='')
    {
        switch(ch)
        {
        case'+':
            stack[top-1]=stack[top-1]+stack[top];
            top--;
            break;
        case'-':
            stack[top-1]=stack[top-1]-stack[top];
            top--;
            break;
        case'*':
            stack[top-1]=stack[top-1]*stack[top];
            top--;
            break;
        case'/':
            if(stack[top]!=0)stack[top-1]=stack[top-1]/stack[top];
            else
            {
                printf("\n\t除零错误!\n");
                exit(0);/*异常退出*/
            }
            top--;
            break;
        default:
            d=0;
            while(ch>='0'&&ch<='9')
            {
                d=10*d+ch-'0';/*将数字字符转化为对应的数值*/
                ch=ex[t];t++;
            }
            top++;
            stack[top]=d;
        }
        ch=ex[t];
        t++;
    }
    printf("\n\t计算结果:%g\n",stack[top]);
}
 
intmain()
{
    trans();
    compvalue();
    system("pause");
    return0;
}


逆波兰算法-二叉树实现

#include <string> 
#include <stack> 
#include <iostream>  
#include <sstream> 
#include <iomanip> 
using namespace std;  

//节点类 
class TNode 
{ 
public: 
    friend class calculator_tree; 
    string father; 
    TNode *left, *right; 
    TNode() 
    { 
        left = right = NULL; 
    } 

    TNode(string a) 
    { 
        father = a; 
        left = right = NULL; 
    } 
}; 


class calculator_tree 
{ 
public: 
    calculator_tree() { 
    } 

    calculator_tree(string expression) { 
        getexpression(expression); 
    } 

    //获得算术表达式 
    void getexpression(string expression) {         e = expression; 
    } 

    ~calculator_tree() { 
    } 

    //返回中缀表达式 
    string ShowMiddleExpression() { 
        return e; 
    } 

    //计算函数, 输入为两个数和一个操作符, 返回值为计算结果(字符串形式) 
    string calculate(string num2, string num1, string op) { 
        double n2, n1; 
        string result; 
        stringstream x; 
        x << num2; 
        x >> n2; 
        x.clear();  
        x << num1; 
        x >> n1; 
        x.clear(); 
        if (op == "+") 
            x << (n2 + n1); 
        if (op == "-") 
            x << (n2 - n1); 
        if (op == "*") 
            x << (n2 * n1); 
        if (op == "/") 
            x << (n2 / n1); 
        x >> result; 
        x.clear(); 
        return result; 
    } 

    //判别符号的优先级 
    int Priority(char a) { 
        if (a == '(') 
            return 0; 
        else if (a == '+' || a == '-') 
            return 1; 
        else if (a == '*' || a == '/') 
            return 2; 
        return 0;     } 


    //用于去除输入中多余的空格 输入为要除去空格的算术表达式 返回去掉空格的算术表达式 
    string RidSpace(string origin) { 
        string transfer; 
        for (int i = 0; i < origin.length(); i++) { 
            if (origin[i] != ' ') 
                transfer += origin[i]; 
        } 
        return transfer; 
    } 

    //中缀表达式转后缀表达式, 因为要兼容多位数, 括号, 负数和小数等功能, 
    //由于多位数在转为后缀表达式时会分不清, 故在每个数和运算符后面加上一个空格作为区别 
    //expression为输出的后缀表达式 
    string MidToLast(string str) { 
        str = RidSpace(str); 
        string expression = ""; 
        string number = ""; 
        char x; 
        stack<char> op; 
        for (int i = 0; i < str.length(); ) { 
            //第一位做特殊处理 判断是否为负号 
            if (i == 0 && str[i] == '-') { 
                number = "-"; 
                i++; 
            } 
            x = str[i]; 
            //录入数字 
            if ((x >= '0' && x <= '9') || number == "-" || x == '.') { 
                while ((str[i] >= '0' && str[i] <= '9') || str[i] == '.') { 
                    number += str[i]; 
                    i++; 
                } 
                expression += number; 
                //加空格以区别 
                expression += " "; 
                number = ""; 
                continue; 
            } else { 
                //判断是括号还是运算符 
                if (x == '(') {                     op.push(x); 
                    //判断是否为负号 
                    if (str[i+1] == '-') { 
                        number = "-"; 
                        i++; 
                      } 
                } else { 
                    //遇到右括号直接弹出运算符栈里的运算符到表达式中 运算符后加空格以区别 
                    if (x == ')') { 
                        while (op.top() != '(') { 
                            expression += op.top(); 
                            expression += " "; 
                            op.pop(); 
                        } 
                        //弹出右括号 
                        op.pop(); 
                      } else { 
                        //弹出栈中优先级较高的运算符 运算符后加空格以区别 
                        while (!op.empty() && (Priority(op.top()) >= Priority(x))) { 
                            expression += op.top(); 
                            expression += " "; 
                            op.pop(); 
                        } 
                        //判断是否为负号 
                        if (str[i+1] == '-') { 
                        number = "-"; 
                        i++; 
                        } 
                        //将运算符压入栈 
                        op.push(x); 
                      } 
                  } 
              } 
              i++; 
            } 
        while (!op.empty()) { 
            expression += op.top(); 
            expression += " "; 
            op.pop(); 
        } 
        return expression; 
    } 
     //获得后缀表达式 
    string GetLastExpression() { 
        return MidToLast(RidSpace(e)); 
    } 


    //生成一棵二叉树 
    void makeTree(TNode *&p) { 
        stack <TNode*> Nodes; 
        string le = GetLastExpression(); 
        string tem = ""; 
            for (int i = 0; i < le.length(); ) { 
                while (le[i] != ' ') { 
                    tem += le[i]; 
                    i++; 
                } 
                //若为数字, 压入结点栈 
                if (tem.length() > 1 || (tem.length() == 1 && tem[0] >= '0' && tem[0] <= '9')) 
                { 
                    p =new TNode(tem); 
                    Nodes.push(p); 
                } else { 
                    //若为运算符 且栈非空 将栈顶元素拿出来分别作为左子树跟右子树的结点 
                    //处理如-()的情况 
                    if (Nodes.empty()) { 
                        tem = "-"; 
                        i++; 
                        continue;
                    } 
                    p = new TNode(tem); 
                    if (!Nodes.empty()) { 
                        p -> right = Nodes.top(); 
                        Nodes.pop(); 
                    } 

                    if (!Nodes.empty()) { 
                        p -> left = Nodes.top(); 
                        Nodes.pop(); 
                    } 
                    Nodes.push(p); 
                } 
                i++; 
                tem = ""; 
            } 
    }  
    //后序遍历二叉树并计算 将计算结果返回 
    string PostOrder(TNode *p) 
    { 
        if(p) { 
          //假如为符号 执行计算后返回计算结果 
            if ((p->father).length() == 1 && Priority((p->father)[0])) { 
                PostOrder(p->right); 
                return calculate(PostOrder(p->left), PostOrder(p->right), p->father); 
            } else { 
                //假如为数字, 直接返回 
                return p->father; 
            } 
        } 
    } 

private: 
    //存放输入的表达式 
    string e; 
}; 



 

后缀表达式生成二叉树

转载请注明涞源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;

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值