数据结构【第八天】:树(二)

二叉树

基本概念

定义:

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

特点:

1、每个结点最多有两棵子树,可以没有或者有一颗

2、左子树和右子树有区别,顺序不可颠倒

3、即使只有一棵子树也需要区分左右

特殊的二叉树:

斜树:所有结点只有左子树,称为左斜树;右斜树同理;

满二叉树:所有分支结点都有左子树和右子树,且所有的叶子均在同一层上

完全二叉树:对一棵具有n个结点的二叉树按层序编号,编号为i的结点与同样深度的满二叉树中编号为i的结点在树中位置完全相同

完全二叉树性质:

1.叶子结点只能出现在最下两层

2.最下层的叶子一定集中在左部连续位置

3.到数第二层若有叶子结点一定都在右部连续位置

4.若结点的度为1,该结点只有左孩子

5.同样结点数的二叉树,完全二叉树的深度最小

二叉树性质:

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

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

3.对任意一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则有n0 = n2 +1

4.具有n个结点的完全二叉树的深度为k,有2^(k-1) = n

5.如果对一棵有n个结点的完全二叉树的结点按层序编号,对任一结点i(1<=i<=n)有:
(1)如果i=1,则该节点为二叉树的根,无双亲;若i>1,则其双亲为【i/2】取整

(2)如果2i>n,则结点i无左孩子,否则其左孩子结点为2i

(3)如果2i+1>n,则结点i无右孩子,否则其右孩子结点为2i+1

存储结构

一、顺序存储结构

       对于完全二叉树而言,其序号与结点的逻辑关系是根据层序关系给定的,即用一维数组可完全代表完全二叉树的结构。但是对于一般二叉树,层序编号不能反映逻辑关系,可把不存在的结点补全,按完全二叉树的方式存储,在不存在的结点设置为空,但是这样对空间的浪费过多。故顺序存储结构一般只用于完全二叉树

二、二叉链表

二叉树的每个结点最多有两个孩子,所以为他们设计一个数据域与两个指针域,指针分别指向左孩子和右孩子。如果需要可以增添一个指向双亲的指针。

结构定义

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

遍历二叉树

二叉树的遍历是指从根节点出发,按照某种次序依次访问二叉树中的所有结点,使每一个结点被访问一次且仅被访问一次

二叉树的定义即是用递归的方式,所以遍历也可以用递归的方式实现。

前序遍历

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

如下的树,前序遍历的顺序为ABDGHCEIF

前序遍历算法

void PreOrderTraverse(BiTree T)
{
    if(T == NULL)
        return;
    std::cout<< T->data;            //显示结点数据
    PreOrderTraverse(T->lchild);    //遍历左子树
    PreOrderTraverse(T->rchild);    //遍历右子树
}

中序遍历

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

如下的树,中序遍历的顺序为GDHBAEICF

中序遍历算法

void InOrderTraverse(BiTree T)
{
    if(T == NULL)
        return;
    InOrderTraverse(T->lchild);    //中序遍历左子树
    std::cout<< T->data;            //显示结点数据
    InOrderTraverse(T->rchild);    //中序遍历右子树
}

后序遍历

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

如下的树,后序遍历GHDBIEFCA

后序遍历算法

void PostOrderTraverse(BiTree T)
{
    if(T == NULL)
        return;
    PostOrderTraverse(T->lchild);    //中序遍历左子树
    PostOrderTraverse(T->rchild);    //中序遍历右子树
    std::cout<< T->data;            //显示结点数据
}

层序遍历

若二叉树为空,则空操作返回,否则从树的第一层,根节点开始,从上向下,从左到右逐个结点访问

如下的树,层序遍历ABCDEFGHI

遍历结果推导

已知前序和中序遍历顺序,可唯一确定一棵二叉树

已知后序和中序遍历顺序,可唯一确定一棵二叉树

但是已知前序和后序,不可以唯一确定一棵二叉树

推导流程:

1.确定根节点

2.确定根节点的左右子节点

3.依次确定剩下的叶子

例:

后序:BDCAFGE

中序:ABCDEFG

解:

1.后序知 根为E

2.中序知 左子树有BDCA 右子树有FG

3.后序知 A为E的左孩子,G是E的右孩子

4.中序知 BCD为A的右子孙,F为G的左孩子

5.在依次分析可知,B为C的左孩子,D为C的右孩子,C为A的右孩子

故前序遍历为EACBDGF

二叉树建立

根据字符建立二叉树,字符为二叉树的遍历方式。例如设二叉树的前序遍历为ABDC,但是为了方便,我们将其扩展为完全二叉树,例如AB#D##C##。然后将这个字符输入构建二叉树,算法如下

void CreatBiTree(BiTree *T)
{
    TElemType ch;
    std::cin>>ch;
    if(ch == '#')
        *T = NULL;
    else
    {
        *T = (BiTree)malloc(sizeof(BiTNode));
        if(!*T)
            exit(OVERFLOW);
        (*T)->data = ch;    //生成根结点
        CreateBiTree(&(*T)->lchild);    //构造左子树
        CreateBiTree(&(*T)->rchild);    //构造右子树
    }
}

如上可见建立二叉树同样是运用了递归的原理,只是将原本的打印换成了生成,同理,修改生成的代码可以满足其他遍历输入构建二叉树

猜你喜欢

转载自blog.csdn.net/KNOW_MORE/article/details/88343775