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

二叉树

时间:2015-05-21 19:36:32      阅读:167      评论:0      收藏:0      [点我收藏+]

标签:二叉树

【二叉树特点】

二叉树由根结点,左子树和右子树构成,具有以下几个典型特点:

  1. 只有一个根节点,每个结点下面最多只有两棵树;
  2. 在二叉树的第i层上至多有2^(i-1)个结点(i>=1);
  3. 深度为k的二叉树至多有(2^k) -1个结点(k>=1);
  4. 对任意一颗二叉树,如果叶子结点数为n0,度为2的结点(结点拥有的子树数就是度)点数为n2,则n0 = n2 + 1;
    对于第4个特点,需要特别解释一下,可以从连接各结点之间的分支线角度来看,结点总数设为n,分支线总数为n-1(规律总结一下就晓得了),度为0的结点就是叶子结点的分支线为0,度为1的结点分支线为1,度为2的分支线为2,故得出n-1= n1*1+n2*2,又有结点总数n = n0+n1+n2,所以综合一下就得到了n0=n2+1。
  5. n个结点的完全二叉树的深度为不大于n的对数的最大值+1,主要是根据第2条特点延伸出来的;
  6. 对一棵n个结点的完全二叉树,结点按层序编号,对任一结点i(1<=i<=n),都有
    如果i=1,结点i就是二叉树的根,无双亲,如果i>1,则其双亲是不大于i/2的结点,例如结点5,其双亲为5/2 =2,就是结点2;
    如果2i>n,则结点i无左孩子,结点i就是叶子结点,否则,其左孩子就是2i;
    如果2i+1>n,则结点i无右孩子,否则右孩子就是2i+1。

【二叉树分类】

二叉树有5种形态:空二叉树,只有一个根结点,只有左子树,只有右子树,既有左子树又有右子树。
技术分享
注意特殊二叉树,包括斜树,满二叉树,完全二叉树。斜树就是只有左子树或者只有右子树的情况;满二叉树就是所有的结点都存在左子树和右子树,并且所有的叶子都在一层上;完全二叉树就是按层序编号从1开始,与满二叉树的位置是一一对应,并且结点按序号依次排列没有空档,就是完全二叉树。
满二叉树
技术分享
完全二叉树
技术分享

【注意】二叉树一定是完全二叉树,但完全二叉树不一定是满二叉树


【基本结构】
二叉树的顺序存储结构就是用一维数组存储二叉树上的点,并且数组的下标能体现结点之间的逻辑关系。
二叉树的链表存储结构类似于利用单链表形式,但是不同的是结点结构除了数据域,还存储了指向左孩子和右孩子的指针,如下

struct BitTreeNode
{
    int data;
    struct BitTreeNode *left,*right;
}

在创建二叉树时,先确定好根结点后再依次添加左右结点。一般采用前序方法创建链表就是先根节点,左孩子,再右孩子,顺序创建,其他也可以,代码方面相应的做修改就好。


【遍历分析】
二叉树操作中最重要的操作就是遍历,有三种,前序遍历,中序遍历,后序遍历。前提是树为空时,空操作返回,
前序遍历:先访问根节点,前序遍历左子树,前序遍历右子树;
中序遍历:中序遍历根节点的左子树,然后访问根节点,最后中序遍历根节点的右子树;
后序遍历:从左到右先叶子后结点的方式遍历访问左右子树,最后访问根节点。
举例如下:
技术分享
前序遍历结果:ABDECF
中序遍历结果:DBEAFC
后序遍历结果:DEBFCA
【测试代码】

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

typedef struct BinaryTreeNode
{
    char data;
    struct BinaryTreeNode *left;
    struct BinaryTreeNode *right;
}Node;
//按照前序输入二叉树中结点的值
//构建二叉树
void create(Node **T)
{
    char ch;
    scanf("%c",&ch);
    if(ch == ‘#‘)
        *T = NULL;
    else
    {
        *T = (Node *)malloc(sizeof(Node));
        (*T)->data = ch;
        create(&(*T)->left);
        create(&(*T)->right);
    }
}
//后序遍历
void post_order_visit(Node **T)
{
    if(*T == NULL)
        return ;
    else
    {
        post_order_visit(&(*T)->left);
        post_order_visit(&(*T)->right);
        printf("%c",(*T)->data);
    }

}
//中序遍历
void in_order_visit(Node **T)
{
    if((*T) == NULL)
        return;
    else
    {
        in_order_visit(&(*T)->left);
        printf("%c",(*T)->data);
        in_order_visit(&(*T)->right);
    }
}
//前序遍历
void pre_order_visit(Node **T)
{
    if((*T) == NULL)
        return;
    else
    {
        printf("%c",(*T)->data);
        pre_order_visit(&(*T)->left);
        pre_order_visit(&(*T)->right);
    }
}
void main()
{

    Node *root=NULL;    
    create(&root);
    printf("后序遍历:");
    post_order_visit(&root);
    printf("\n");
    printf("中序遍历:");
    in_order_visit(&root);
    printf("\n");
    printf("前序遍历:");
    pre_order_visit(&root);
    printf("\n");
}

【输出】
技术分享
验证结果正确。
【二叉树延伸】
对于一个二叉树遍历的问题,通常是已知一个二叉树的两种遍历结果,通过推导得到二叉树的另一种遍历结果,首先要牢牢掌握住前序遍历,中序遍历,后序遍历的方法思想,这样就不难了。
已知前序遍历序列和中序遍历序列,可以唯一确定一棵二叉树;
已知后序遍历序列和中序遍历序列,可以唯一确定一棵二叉树。
但是,已知前序和后序是不能确定一棵二叉树的,可能性太多。
就以上面测试用例中结果来详细分析一下过程:
前序:ABDECF, 中序:DBEAFC
前序是根->左->右,中序是左->根->右
从前序来看A必然是根节点,由中序看,那么A左边的必然是左子树,A右边的必然是右子树,分析左子树元素DBE,前序是BDE,综合中序和前序特点,B必然是DE的根,进而D,E分别为B的左孩子和右孩子,后序结果就是DEB,而FC是右子树,也是结合排序特点,得到F是C的左孩子,C为F的根,后序结果FC。综合根节点A,后序结果就是DEBFCA。

二叉树

标签:二叉树

原文地址:http://blog.csdn.net/xinyu913/article/details/45893767

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