【 数据结构--树】

树的概述

1.树的定义

树(Tree)是n(n>0)个节点的有限集合T,n=0的树称为空树,当n>0的时候满足如下两个条件:

(1)有且仅有一个特定的称为根的节点

(2)当n>1时,其余节点可分为m(m>0)个互不相交的有限集T1、T2、....、Tm,其中每一个集合本身又是一颗树,并称为根的子树。

 

             (a)图示法                                      (b)集合表示法           (c)横向凹入表表示法

                                                            图 6.2       树的表示方法

2.树的特点

1)有且仅有一个结点没有直接前趋,称它为根结点
2)有1个多个结点没有直接后继,称它为终端结点也即叶子结点
3)除根结点外,树中其它任一结点都有且仅有一个直接前趋;
4)除终端(叶子)结点外,树中其它任一结点都有一个多个直接后继。

3.树的基本术语

结点(node):表示树中的元素,包括数据项及若干指向其子树的分支。
结点的度(degree):结点拥有的子树的数目。图中结点A的度为3。   
叶子(leaf):度为0的结点称为叶子结点,也称为终端结点。图中,叶子结点有:K,L,F,G,M,I,J。
分支结点:度不为0的结点称为分支结点,也称为非终端结点。图中,非终端结点有:A,B,C,D等

孩子结点(child):结点的子树的根称为该结点的孩子结点。图中,结点A的孩子结点为B,C,D,结点B的孩子结点为E,F。
双亲结点(parents):孩子结点的上层结点称为该结点的双亲结点。图中,结点I的双亲为D,结点L的双亲为E。  
兄弟结点(sibling):具有同一双亲结点的孩子结点之间互称为兄弟结点。图中,结点B,C,D互为兄弟,结点K,L互为兄弟。
祖先结点:从根到该结点所经分支上的所有结点。图中,对于结点M来说,A,D,H都是它的祖先  树的度:树中最大的结点的度数即为树的度。图中的树的度为3。
结点的层次(level):从根结点算起,根为第一层,它的孩子为第二层……。若某结点在第i层,则其孩子结点就在第i+1层。图中,结点A的层次为1,结点M的层次为4。
树的高度或深度(depth):树中结点的最大层次数。图6中的树的高度为4。  
森林(forest):m(m≥0)棵互不相交的树的集合。对树中每个结点而言,其子树的集合即为森林。若将图中根结点A删去,则树就变为由3棵树组成的森林。

二叉树

 1.二叉树的定义

二叉树是由n(n≥0)个结点的有限集T构成,此集合或者为空集,或者由一个根结点及两棵互不相交的左右子树组成,并且左右子树都是二叉树。

2.二叉树的特点

(1)有且仅有一个称为root的根结点。
(2)每个结点最多有两棵子树(即二叉树中结点的度不大于2),没有子树或只有一棵子树都可以.
(3)子树有左右之分,次序不能任意颠倒;树中某结点即使只有一棵子树,也要区分左右 。

3.二叉树的五种基本形态

                                                 图 6.3    二叉树的五种基本形态

4.二叉树的性质

性质1 在二叉树第i层上最多有2^(i-1)个节点

用归纳法证明此性质:
当i =1时,只有一个根结点,显然2^(i-1) = 2^(1-1) = 2^0 =1;
第二层有2个,i=2时, 2^(i-1) = 2^(2-1)= 2^1=2
第三层有4个,i=3时, 2^(i-1) = 2^(3-1) = 2^2=4
第三层有8个,i=4时, 2^(i-1) = 2^(4-1) = 2^3=8
……..
通过数学归纳法的论证,可以得出第i层上至多有结点数
                             2*2^(i-2)= 2^(i-1)

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

用归纳法证明此性质:
如果有1层(深度k=1),则至多1=2^1-1个结点;
如果有2层(深度k=2),则至多1+2=3=2^2-1个结点;
如果有3层(深度k=3),则至多1+2+4=7=2^3-1个结点;如果有4层(深度k=4),则至多1+2+4+8=15=24-1个结点;
通过数学归纳法的论证,可得,如果有k层,则该二叉树至多有2^k-1个结点。

性质3  对任意一棵二叉树BT,如果其叶子结点数为n0度为2的结点数为n2,则n0=n2+1

证明: 换个角度,用连接线数(孩子结点数)来算结点数。
1)度为2的结点( A,B,C,D )都有两条连接线,即有2个孩子结点, (4*2);
2)度为1的结点( E )有一条连接线,即有1个孩子结点1*1);
3)根结点不是任何节点的孩子,没有连接线进入;叶子节点没有任何孩子
因此总结点n=n0*0+n1*1+n2*2+1=4*2+1+1=10    (2)

由公式1和公式2可得   n=n0+n1+n2=n1+n2*2+1  
因此 n0=n2+1

5.二叉树的存储顺序

 (1)顺序存储结构

这种存储方式适用于完全二叉树和满二叉树。用一组地址连续的存储单元(一维数组)依次自上而下、自左至右存储二叉树上的结点元素。结点的存储位置(数组下标)要能体现结点间的逻辑关系。比如双亲孩子的关系,左右兄弟的关系等。

 (2)链式存储结构

二叉树通常采用链式存储结构存储二叉树中的结点及其相互之间的关系。
二叉树每个结点最多有2个孩子,所以为它设计一个数据域和两个指针域的结点结构,这样的链表称为二叉链表。

lchilddaterchild

  (a)二叉链表的结点结构

lchilddateparentrchild

  (b)三叉链表的结点结构

二叉链表中节点结构在C语言中的类型定义。

typedef struct BiTNode

DataType data;                                             //节点的数据元素

struct BiTNode *lchild, *rchild;                      //左右孩子指针

} BiTNode, *BiTree;

 (a)二叉树                                            (b)二叉链表存储结构

                                              图 6.10 二叉树及其二叉链表存储结构

二叉树的遍历

遍历二叉树(Traversing Binary Tree):是指沿着某条搜索路径访问二叉树的每个节点,并且使得每个节点被访问一次且仅被访问一次。

访问是指对节点做某种处理,是抽象操作,要根据实际需要来确定具体做什么,比如:输出节点信息、修改节点的值、增加删除节点等。

二叉树的遍历不同于线性结构,因为线性结构的遍历方式是从头到尾、循环、双向等简单遍历。而二叉树的每个结点可以有两个孩子节点,即在访问一个结点后,下一个被访问的结点面临不同的选择(左孩子或右孩子),选择方式不同,遍历次序完全不同。

由于二叉树的基本组成为根结点、左子树、右子树,因此,若能依次遍历这三部分,就是遍历了二叉树。

若以L、D、R分别表示遍历左子树、遍历根结点和遍历右子树,则有六种遍历方法:DLR、LDR、LRD、DRL、RDL、RLD。前3种和后3种遍历序列相反,但算法设计相似。
若规定先左后右,则只有前三种情况,分别是:
1)DLR——先(根)序遍历(先访问树的根结点,然后依次先根遍历根的左子树和右子树)。
2)LDR——中(根)序遍历(先中跟遍历左子树,再访问根结点,最后中跟遍历右子树)。
3)LRD——后(根)序遍历(先依次后根遍历左子树和右子树,然后访问根结点)。

        4)层序遍历—常见的遍历方式,从树的第一层,即根结点开始访问,从上而下逐层遍历,在同一层中,按从左到右的顺序对结点逐个访问。

1)先根遍历二叉树:   若二叉树为空,则遍历结束;否则
 (1)访问根结点;
 (2)先根遍历左子树;
 (3)先根遍历右子树。

遍历顺序为:ABDGHCEEIF

 2)中根遍历二叉树:   若二叉树为空,则遍历结束;否则
 (1)中根遍历左子树;
 (2)访问根结点;
 (3)中根遍历右子树。

遍历顺序为:GDHBAEICF

3)后根遍历二叉树:   若二叉树为空,则遍历结束;否则
 (1)后根遍历左子树;
 (2)后根遍历右子树;
 (3)访问根结点。

遍历顺序为:GHDBIEFCA

4)层序遍历二叉树:   若二叉树为空,则遍历结束;否则
从树的第一层,即根结点开始访问,从上而下逐层遍历,在同一层中,按从左到右的顺序对结点逐个访问

遍历顺序为:ABCDEFGHI

算法6.1 先根遍历的递归算法。

void PreOrderTraverse(BiTree T)

{

/*先根遍历二叉树*/

if(T)

     {

printf("%c",T->data);

PreOrderTraverse(T->lchild);

PreOrderTraverse(T->rchild);

    }

}

算法6.2 中根遍历的递归算法

void InOrderTraverse(BiTree T)

{

/*中根遍历二叉树*/

if(T)

     {

InOrderTraverse(T->lchild);

printf("%c",T->data);

InOrderTraverse(T->rchild);

    }

}

算法 6.3 后根遍历的递归算法

void PostOrderTraverse(BiTree T)

{

/*后根遍历二叉树*/

if(T)

     {

PostOrderTraverse(T->lchild);

PostOrderTraverse(T->rchild);

printf("%c",T->data);

    }

}

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值