码迷,mamicode.com
首页 > 其他好文 > 详细

二叉树 二叉树的性质 存储结构 遍历二叉树 C实现二叉树的创建和遍历 线索二叉树

时间:2015-07-07 09:40:05      阅读:170      评论:0      收藏:0      [点我收藏+]

标签:二叉树   二叉树存储结构   遍历二叉树   代码实现二叉树   线索二叉树   

定义

二叉树(binary tree)是n(n>=0)个结点的有限集合,该集合为空集合称为空二叉树,或者有一个根结点和两棵互不相交的,分别称为树根结点的左孩子树和右孩子树组成.

二叉树的特点

  • 每个结点最多有两棵子树,所以二叉树总没有度大于2的结点
  • 左子树和右子树是有顺序的,次数不能任意颠倒
  • 即使树中某结点只有一棵子树,也要区分是左子树还是右子树

特殊的二叉树

1. 斜树

所有的结点都只有左子树的二叉树称为左斜树;
所有的结点都只有右子树的二叉树称为右斜树;
这两者统称为斜树

2. 满二叉树

在一棵二叉树中,如果所有的分支节点都存在左子树和右子树, 并且所有的叶子都在同一层上,这样的二叉树称为满二叉树.

特点

  • 叶子只能出现在最下一层,出现在其它层就不可能达成平衡.
  • 非叶子结点的度一定是2.
  • 在同样的深度的二叉树中,满二叉树的结点个数最多,叶子数也最多.

3. 完全二叉树

对一棵具有n个结点的二叉树按层序编号,如果编号为i(1 <= i <= n)的结点与同样深度的满二叉树中编号为i的结点在二叉树中位置完全相同,则这棵二叉树称为完全二叉树.

满二叉树一定是完全二叉树, 但完全二叉树不一定是满二叉树

特点

  • 叶子结点只能出现在最下两层.
  • 最下层的叶子一定集中在左部连续位置.
  • 倒数二层,若有叶子节点,一定在右部连续位置
  • 如果结点度为1,则结点只有左孩子,即不存在只有右子树的情况
  • 同样结点数的二叉树,完全二叉树的深度最小

二叉树的性质

性质1

在二叉树的第i层上至多有 2^(i-1) 个结点(i>=1)

性质2

深度为k的二叉树至多有 2^(k)-1 个结点(k>=1)

性质3

对任何一棵二叉树T,如果其终端结点数的n0, 度为2的结点数为n2 则n0 = n2 + 1
树T结点的总数为n=n0+n1+n2
分支结点数= n - 1 = n1 + 2*n2

性质4

具有n个结点的完全二叉树的深度为└ log2^n ┘ + 1 (└ x ┘表示不大于x的最大整数)

性质5

如果对一棵有n个结点的完全二叉树(其深度为 └ log2^n ┘ + 1 )结点按层序编号(从第1层到 └ log2^n ┘ + 1 层,每层从左到右)对任一结点i(1 <= i <=n)有

  1. 如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲结点是: └ i/2┘
  2. 如果2i>n,则结点i无左孩子(结点i为叶子结点);否则器左孩子是结点2i
  3. 如果2i+1>n,则结点i无右孩子,否则其右孩子是结点2i+1

二叉树的存储结构

1. 顺序存储结构

由于二叉树的严格的定义 可以采用一维数组存储二叉树中的结点,并且结点的存储位置,也就是数组的下标要能提现结点之间的逻辑关系,比如双亲和孩子的关系,左右兄弟的关系等.

对于一般的二叉树,尽管层序编号不能反映逻辑关系, 可把不存在的结点设置为^便可.

顺序存储结构一般只用于完全二叉树

2. 二叉链表

二叉树每个结点做多有两个孩子,所以他设计一个数据域和两个指针域是比较自然的想法,我们称这样的链表为二叉链表.

左孩子指针域 数据域 右孩子指针域
lchild data rchild

遍历二叉树

二叉树的遍历是指(traversing binary tree): 从根结点出发,按照某种次序一次访问二叉树中所有的结点,使得每个结点被访问一次且仅被访问一次.

1. 前序遍历

若二叉树为空,则空操作返回,否则先访问根结点,然后前序遍历左子树,在前序遍历右子树.

2. 中序遍历

若二叉树为空,则空操作返回,否则先从根结点开始(并不是先访问根结点),中序遍历根结点的左子树,然后访问根结点,最后中序遍历右子树.

3. 后序遍历

若二叉树为空,则空操作返回,否则先从左到右先叶子后结点的方式遍历访问左右子树,最后是访问根结点.

4. 层序遍历

若二叉树为空,则空操作返回,否则先从树的第一层,也就是从根结点开始访问,从上而下逐层访问,在同一层中,按从左到右的顺序对结点逐个访问.

四种遍历方式,都是把树中的结点变成某种意义的线性序列,给程序的实现带来了好处

代码实现二叉树的建立和遍历

/*
    二叉树(binary tree) - 链式存储结构
    实现 二叉树的创建和遍历
    遍历和创建分为三种 前序,中序,后序 
    输入 数据参考 <AB D  C  > 空格是要输入 的 
*/

#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR 0;

typedef int Status;
typedef char TElemType;

//结点定义
typedef struct BiTNode {
    TElemType data;     //数据域 
    struct BiTNode *lchild, *rchild;    //左右孩子指针 
}BiTNode, *BiTree;

//前序遍历(previous order traverse)
void preOrderTraverse (BiTree T){
    if(T == NULL){
        return;
    } 
    printf("%c ", T->data);         //第一步 显示结点数据
    preOrderTraverse(T->lchild);    //第二步 前序遍历左子树 
    preOrderTraverse(T->rchild);        //第三步 前序遍历右子树 
}

//中序遍历(intermediate order traverse)
void inOrderTraverse (BiTree T){
    if(T == NULL){
        return;
    } 
    inOrderTraverse(T->lchild); //第一步 中序遍历左子树 
    printf("%c ", T->data);     //第二步 显示结点数据
    inOrderTraverse(T->rchild); //第三步 中序遍历右子树 
}

//后序遍历(post order traverse)
void postOrderTraverse(BiTree T){
    if(T == NULL){
        return;
    }
    postOrderTraverse(T->lchild);
    postOrderTraverse(T->rchild);
    printf("%c ", T->data);
} 

//二叉树的建立  按前序输入二叉树中结点的值 (一个字符)
//‘ ‘表示空树 让每个结点确定是否有左右孩子,构造二叉链表表示二叉树 
//如果输入顺序按中序或后序 , 代码的66 67 68行顺序要换一下 ,可以参照遍历的代码这里就不实现了. 
void createBiTree(BiTree *T){
    TElemType e;
    scanf("%c",&e);
    if(e == ‘ ‘){
        *T = NULL;
    } 
    else{
        *T = (BiTree)malloc(sizeof(BiTNode));   //生成结点 
        if(!(*T)){  //创建失败 
            printf("结点申请失败\n"); 
            return; 
        }
        (*T)->data = e; //给结点赋值
        createBiTree(&(*T)->lchild); //构造左子树
        createBiTree(&(*T)->rchild);    //构造右子树 
    } 
}

int main(void){
    BiTree T;
    TElemType e;
    int option = 1;
    printf("\n 1.前序创建二叉树\n 2.前序遍历二叉树\n 3.中序遍历二叉树\n 4.后序遍历二叉树\n 0.退出\n");
    while(option){
        scanf("%d", &option);
        fflush(stdin);  //刷新缓冲区 这个是必须的 不然创建的时候输入数据会让你疑惑 
        switch(option){
            case 1:
                createBiTree(&T);
                printf("二叉树创建成功\n");
                break;
            case 2:
                preOrderTraverse(T);
                break;
            case 3:
                inOrderTraverse(T);
                break;
            case 4:
                postOrderTraverse(T);
                break;
            case 0:
                return OK; 
        }
    } 
    return OK;
}
注意: 建立的时候 每个结点确定是否有左右孩子,如果没有则用空格代替

缺点

浪费空间,有很多的空指针域 最有有n+1个空指针

二叉树的建立和遍历都是递归的原理
建立 是在原来的打印结点的地方,改成了生成节点,给结点赋值的操作而已.

n个结点有2n个指针域,而n个结点的二叉树一共有n-1条分支线,所以空指针域 = 2n-(n-1) = n+1

线索二叉树

指向前驱和后继的指针称为线索,加上线索的二叉链表称为线索链表,相应的二叉树就称为线索二叉树

为了解决二叉树中空指针域浪费的问题 将空指针利用起来,指向前驱和后继 这种思想称为线索二叉树

优点

便于查找结点
遍历二叉树效率高
便于超找结点的前驱和后继.

版权声明:本文为博主原创文章,未经博主允许不得转载。

二叉树 二叉树的性质 存储结构 遍历二叉树 C实现二叉树的创建和遍历 线索二叉树

标签:二叉树   二叉树存储结构   遍历二叉树   代码实现二叉树   线索二叉树   

原文地址:http://blog.csdn.net/u010187139/article/details/46778661

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!