AKever

导航

Others(1) 二叉树de解析

二叉树de解析

转自:http://hi.baidu.com/huahua035/item/d3cb61262634edd2a517b6be

数据结构中的二叉树是一种非常重要的非线性结构。
对于二叉树,最重要的算法就是二叉树的遍历,根据访问节点的顺序,分为三种
遍历方法:
前序遍历:(NLR)先访问根节点,然后访问左节点,最后访问右节点
中序遍历:(LNR)先访问左节点,然后访问根节点,最后访问右节点
后序遍历:(LNR)先访问左节点,然后访问右节点,最后访问根节点
很清晰的可以看出,其实它就是根据根节点的访问次序区分的。
下面这个图就可以清晰的看出这三种遍历方法的区分:

 

存储结构
主要分两种:线性存储结构和链式存储结构。
线性存储:就是存储在数组中,这时候有一个很重要的问题:二叉树的节点以什么顺序存储在数组中?这种顺序必须体现出二叉树的父子关系。
解决办法就是:
1. 把每棵树都看作是一个满二叉树(满二叉树就是除了叶子节点每个节点都有左右子节点),如果这棵树是非满二叉树,就主动给它补全,而补上的节点都是NULL;
2. 按层遍历;
为了说明问题,以上面的那棵完全二叉树为例说明:
它的存储结构结构是
A B C D E F G NULL NULL NULL NULL H NULL NULL NULL
说明:
前三层是完整的,按层顺序访问就是A B C D E F G
第四层中,应该是找出D E F G的8个子节点,D E没有。OK,就补了4个NULL值,F只有左节点,所以它的两个子节点为H NULL,G没有子节点,那就是两个NULL NULL
这下,就可以通过解析数组,清晰的把各个节点的父子结构拿出来了。
链式存储:
这个估计基本不用解释,大家都知道咋存储了,因为很简单,它就是用一个二叉链表存储的:
左节点地址
自身值
右节点地址
这个大家都很容易理解,我们只要知道了这棵树的根节点,就可以访问到它所以的节点值了。
二叉树存储结构分析:
我们知道,数组的优点是可以随机访问,因为它有下标,但是插入和删除比较麻烦,尤其是从第一位就删除或插入,需要移动整个数组;而链表正好相反,插入和删除非常方便,这要修改它的左右值就可以,但是随机访问不方便,因为它需要顺序的遍历;
二叉树的存在意义
二叉树具有两种数据结构的优点:一种是有序数组,一种是链表;在树中查找数据项的速度和有序数组一样快,在树中添加和删除数据和链表一样快。

 

Code

转自:http://baike.baidu.com/link?url=tDsct2Vy118Ym3GrtZ_XHFTnEQ7ourjEgrExFpZt4Ps4ffzwhv1jZ9ZQNP8V0r8M

typedef struct CSNode{
    ElemType data;
    struct CSNode *firstchild , *netsibling;
} CSNode,* CSTree;

bitree.h

//二叉链表定义
#include <iostream>

using namespace std;
typedef char TElemType;

struct BiTNode{
    TElemType data;
    BiTNode *lchild,*rchild;
};

typedef BiTNode *BiTree;
void initBiTree(BiTree &T);
void createBiTree(BiTree &T);
void preOrderTraverse(BiTree T,void (*visit)(TElemType)); //递归前序遍历
void preOrderTraverse1(BiTree T,void (*visit)(TElemType)); //非递归前序遍历
void inOrderTraverse(BiTree T,void (*visit)(TElemType)); //递归中序遍历
void postOrderTraverse(BiTree T,void (*visit)(TElemType)); //递归后序遍历
void levelOrderTraverse(BiTree T,void (*visit)(TElemType)); //层序遍历

bitree.cpp

#include "bitree.h"
void initBiTree(BiTree &T){ //构造空二叉树T
    T=NULL;
}
void createBiTree(BiTree &T){
    //按先序次序输入二叉树中结点的值('#'表示空格),构造二叉链表表示的二叉树T。
    TElemType ch;
    cin>>ch;
    if(ch=='#') //
    T=NULL;
    else{
        T=new BiTNode;
        if(!T)
        exit(1);
        T->data=ch; // 生成根结点
        createBiTree(T->lchild); // 构造左子树
        createBiTree(T->rchild); // 构造右子树
    }
}
void preOrderTraverse(BiTree T,void (*visit)(TElemType)){
    // 先序递归遍历T,对每个结点调用函数Visit一次且仅一次
    if(T){ // T不空
        visit(T->data); // 先访问根结点
        preOrderTraverse(T->lchild,visit); // 再先序遍历左子树
        preOrderTraverse(T->rchild,visit); // 最后先序遍历右子树
    }
}
void preOrderTraverse1(BiTree T,void (*visit)(TElemType)){
    //前序遍历二叉树T的非递归算法(利用栈),对每个数据元素调用函数Visit
    BiTree s[100];
    int top=0; //top为栈顶指针
    while((T!=NULL)||(top>0)){
        while(T!=NULL){
            visit(T->data);
            s[top++]=T;
            T=T->lchild;
        }
        T=s[--top];
        T=T->rchild;
    }
}
void inOrderTraverse(BiTree T,void (*visit)(TElemType)){
    //中序递归遍历T,对每个结点调用函数Visit一次且仅一次
    if(T){
        inOrderTraverse(T->lchild,visit); // 先中序遍历左子树
        visit(T->data); // 再访问根结点
        inOrderTraverse(T->rchild,visit); // 最后中序遍历右子树
    }
}
void postOrderTraverse(BiTree T,void (*visit)(TElemType)){
    //后序递归遍历T,对每个结点调用函数Visit一次且仅一次
    if(T){
        inOrderTraverse(T->lchild,visit); // 后序遍历左子树
        inOrderTraverse(T->rchild,visit); // 再后序遍历右子树
        visit(T->data); // 最后访问根结点
    }
}
void levelOrderTraverse(BiTree T,void (*visit)(TElemType)){
    //层序遍历T(利用队列),对每个结点调用函数Visit一次且仅一次
    BiTree q[100],p;
    int f,r; // f,r类似于头尾指针
    q[0]=T;
    f=0;
    r=1;
    while(f<r){
        p=q[f++]; //出队
        visit(p->data);
        if(p->lchild!=NULL)
        q[r++]=p->lchild; //入队
        if(p->rchild!=NULL)
        q[r++]=p->rchild; //入队
    }
}

 

 

posted on 2014-02-07 09:36  AKever  阅读(287)  评论(0)    收藏  举报