mu_tou_man

导航

 

更多二叉树相关概念请看http://blog.csdn.net/zhang_xinxiu/article/details/12904635

 

一、二叉树相关概念:

  1. 路径:对于节点n1 n2 n3….nk从n1到nk的路径长度为k-1
  2. 节点的层数:只有一个根节点,则层数为1,其余节点的层数为双亲节点的层数加1
  3. 树的深度:树中所有节点的最大层数称为树的深度,只有根节点深度为1。
  4. 满二叉树:所有分支节点存在左子树和右子树,并且所有的叶子节点都在同一层上。
  5. 完全二叉树:对于树中的节点从上至下、从左到右顺序进行编号,且与满二叉树的位置编号相同。完全二叉树特点:叶子节点只能出现在最下层和次下层,且最下层的叶子节点集中在树的左边,满二叉树肯定是完全二叉树,反之不一定。如果完全二叉树中子节点个数分别为0、1、2的节点数分别用n0 n1 n2表示,节点总数n=n0+n1=n2,且n1只能为0或者1。

二、二叉树相关性质:

  1. 一颗深度为k的二叉树中,最多有2的k次方-1个节点(满二叉树),最少有k个节点
  2. 对于一颗非空二叉树,度为0的节点总是比度为2的几点多一个,即:n0=n2+1;
  3. 具有n个节点的完全二叉树的深度为【logn】+1,【】为向下取整;
  4. 对于n个节点从1开始编号的完全二叉树,对于节点编号i的节点:

    (1)如果2i<=n,则序号为i的节点的左孩子节点的序号为2i;如果2i>n,则序号为i的节点无左孩子;

       (2)如果2i+1<=n,则i节点有孩子序号为2i+1,如果2i+1>n,则i无右孩子。

                                                                                                                                                                 

三、二叉树的遍历:

  1、先序遍历:先序遍历是先输出根节点,再输出左子树,最后输出右子树。上图的先序遍历结果就是:ABCDEF

  2、中序遍历:中序遍历是先输出左子树,再输出根节点,最后输出右子树。上图的中序遍历结果就是:CBDAEF

  3、后序遍历:后序遍历是先输出左子树,再输出右子树,最后输出根节点。上图的后序遍历结果就是:CDBFEA

#include <iostream>
using namespace std;
struct TNode
{
    TNode * LeftChild;
    TNode * RightChild;
    char data;
};

TNode *CreateTree()
{
    TNode *pRoot=NULL;
    char data=0;
    cin>>data;
    if (data=='#')
    {
        pRoot=NULL;
    }
    else
    {
        pRoot=(TNode*)malloc(sizeof(TNode));
        pRoot->data=data;
        pRoot->LeftChild=CreateTree();
        pRoot->RightChild=CreateTree();
    }
    return pRoot;
}

void PreTraverse(TNode *pRoot)
{
    if (pRoot==NULL)
    {
        return;
    }
    cout<<pRoot->data<<' ';
    PreTraverse(pRoot->LeftChild);
    PreTraverse(pRoot->RightChild);
}

void InTraverse(TNode *pRoot)
{
    if (pRoot==NULL)
    {
        return;
    }
    InTraverse(pRoot->LeftChild);
    cout<<pRoot->data<<' ';
    InTraverse(pRoot->RightChild);
}

void LastTraverse(TNode *pRoot)
{
    if (pRoot==NULL)
    {
        return;
    }
    LastTraverse(pRoot->LeftChild);
    LastTraverse(pRoot->RightChild);
    cout<<pRoot->data<<' ';
}
void main()
{
    TNode *root=CreateTree();
    cout<<"first order is:  ";
    PreTraverse(root);
    cout<<endl;
    cout<<"middle order is: ";
    InTraverse(root);
    cout<<endl;
    cout<<"last order is:   ";
    LastTraverse(root);
    cout<<endl;
}

 

 输出结果如下图:

 

四、二叉树删除操作

 

 

  如右图,要删除B节点,要将D节点放入B的左孩子最右下孩子之后,也就是D’的位置。

    A.left=B.left;

    p=B.left;//也就是C

    while(p.right!=null)

           p=p.right;

 

    p.right=B.right;

    free(B);

 

五.建立完全二叉树

         建立完全二叉树之前先给出遍历类型,例如,先序遍历:那么就用#

来代替空值,例如如下序列:ABC###DEF##G###就表示如下的树型:

 

 

 

 

 

 

 

 

 

 

六.遍历树的推导

  对于一颗二叉树可以根据前序遍历中序遍历推测出后续遍历,也可以根据中序遍历后续遍历推测出前序遍历,但是不可以根据前序遍历和后续遍历推测出中序遍历。

  我们用D来表示父节点,L表示左孩子,R来表示右孩子。

    前序遍历就是DLR

    中序遍历就是LDR

    后续遍历就是LRD

  例如一棵树的前序遍历是ABDECF 中序遍历为DBEAFC如何求后续遍历?

           前序遍历第一个字母A肯定是树根,然后根据中序遍历可以划分左右子树,DBE|A|FC,接下来再看左子树DBE,根据前序遍历第一个字母是B可以推断B是左子树的树根,  再看其中续遍历DBE,可以推断出D是其左子树,E是其右子树。同理可以推测出FC。结果显而易见。

 

七、二叉分类树

         如果一棵树是二叉分类树,那么对于任何节点,其左儿子<=父节点<右儿子,对该树进行中序遍历可以得到顺序序列。

 

八、扩充二叉树

         将原来每个节点的空指针都指向一个特殊的节点—外节点,这样的二叉树称为扩充二叉树。

         对于有n个节点的二叉树,含有2n个指针域,但是总共只有n-1条路径,所以占用n-1个指针域,剩余指针域为2n-n+1=n+1个,

   所以

      外节点个数=内节点个数+1.

      外路径长度=内路径长度+2n

九、平衡二叉树

 

         当且仅当每个节点的左右子树高度至多相差1时,我们称这样的树为平衡树。

         如果BF的绝对值小于等于1,那么就是平衡二叉树。         平衡因子:BF=左子树高度-右子树高度

         对于右面这棵树BF(A)=-2;BF(E)=-1;BF(F)=0;

         所以该树不是平衡二叉树。

      当用一个数字序列构造平衡二叉树的时候,如果有结点出现BF=-2,那么调节离插入节点最近的BF=-2的节点,如右图,如果A<E<F            可能使E为树根,A、F分别为左右子树.

 

十、哈弗曼树

  详见http://blog.csdn.net/zhang_xinxiu/article/details/12704337

 

posted on 2014-08-12 20:03  mu_tou_man  阅读(508)  评论(0编辑  收藏  举报