数据结构之树(Tree)(一)_树的基础

该篇是关于树的概述,主要介绍什么是树、树的特点、树的表示方法、树的种类、树在存储结构中的表示、树/森林/二叉树之间的转换(原理)等,关于具体树(二叉树)的实现以及查找遍历等后续总结。

树的概述及特点

树是由n个(n>=0)结点组成的一个具有层次关系的集合。
如图,是一个普通的树的图像表示:
tree1
从这个图像中大致能看出为什么把这种层次关系的集合称为树了,这个就像一个倒着的树,树跟在上,树叶在下,中间是树干。

由 m(m >= 0) 个互不相交的树 组成的集合被称为森林。如上图,若以B、C为根节点的2棵子树就可以称为森林。

树的结点

树中的每个元素成为“结点”。

特殊的结点
  • 根结点:没有父结点的结点。如上图的A。
  • 叶子结点:没有子结点的结点,如上图的D、E、F、C都是叶子结点。
结点之间的特殊关系
  • 父结点(或称为双亲结点):一个结点含有子结点,那么该结点称为其子结点的父结点。如上图,A是B、C的父结点。
  • 子结点(或称为孩子结点):子结点和父结点是相对的。如上图,B、C就是A的子结点。
  • 兄弟结点:具有相同的父结点称为兄弟结点。如上图,B、C即是兄弟结点,D、E、F也是兄弟结点。

树的特点

  • 每个结点有0个或多个子结点。
  • 非空树有且只有一个根结点。
  • 非根结点有且只有一个父结点。

几个概念

  • 结点的度:一个结点含有的子结点数,即结点的度。如上图,A结点的度为2,B结点的度为3。
  • 树的度:一颗树中所有结点的度的最大值即树的度。如上图,树的度是3。
  • 结点的层次:从根结点开始,根结点为第一层,根结点的子结点为第二层,依次类推。如上图,A为第一层,B、C为第二层,D、E、F为第三层。
  • 树的高度(或树的深度):树中结点所在最大层次。如上图,树的高度即3。

树的表示方法

树的表示方法有很多,最常用的就是图像表示法。
这里就介绍两种比较常见的,图像表示法和符号表示法。

  • 图像表示法

如最开始的图像表示(如上图)。各结点之间的关系很清晰。

  • 符号表示法

用括号先将根结点放入一对圆括号中,然后把它的子树由左至右的顺序放入括号中,而对子树也采用同样的方法处理,同层子树之间用逗号隔开。上图用符号表示法表示为:(A(B(D,E,F),C))

树的种类

有序树与无序树

树中结点的子结点之间是否有顺序关系,即谁在左边、谁在右边是否有规定的。
这种,如果有规定 即子结点之间存在顺序关系,称为有序树
相反,如果不存在顺序关系,则称为无序树

二叉树

二叉树是非常重要的一种,后续很多都与之关联。

先看个示例图:
tree_different

每个结点最多含有两个子树的树称为二叉树。 二叉树是有序树。
即各个结点的度不超过2。(也即直接的子结点数最多为2,上面讲的子结点、父结点基本都是直接的关系,不包含子结点的子结点或父结点的父结点)

二叉树的一些特性:
1.第i层,结点总数最多为:2i-1
2.若树的深度为k,则二叉树结点总数最多为:2k-1。
3.叶子节点数n0 与 度为2的结点数n2 的关系:n0 =n2+1。

两种特殊二叉树

  • 满二叉树

除叶子结点外,其他结点的度都是2(即只有两个子结点)的树 称为满二叉树。

满二叉树的一些特性:
1.满二叉树第i层,结点总数为:2i-1
2.若树的深度为k,则满二叉树结点总数为:2k-1,叶子结点树为:2k-1
3.满二叉树叶子节点都在对地层,不存在度为1的结点。
4.满二叉树,若有n个结点,则树的深度为:k=log2(n+1)。 2k-1=n

  • 完全二叉树

假设其深度为d(d>1)。除了第d层外,其它各层的节点数目均已达最大值,且第d层所有节点从左向右连续地紧密排列,这样的二叉树称之为完全二叉树。
即:如果二叉树中除去最后一层节点为满二叉树,且最后一层的结点依次从左到右分布,则此二叉树被称为完全二叉树。

完全二叉树的一些特性:
1.完全二叉树若结点总数为n,则树的深度为:⌊log2n⌋+1。
⌊ ⌋为取整,如⌊log26⌋+1=3
2.假如完全二叉树中结点编号从上到下,从左到右依次从1到n。则有:
如果i>1时,父结点为⌊i/2⌋。(i=1即根结点,无父结点)。
如果2i>n, 则i无左孩子(为叶子结点);否则i的左孩子是2i。
如果2i+1>n, 则i无右孩子;否则i右孩子是2i+1.

  • 平衡二叉树(AVL树)

当且仅当任何节点的两棵子树的高度差不大于1的二叉树

树在存储结构中的表示

树在存储结构中的表示,主要有3种:双亲表示法、孩子表示法、孩子兄弟表示法

双亲表示法

双亲表示法,采用数组的存储方式。
每个结点包含两个部分:数据部分和指向父结点(双亲结点)的指针。
数组元素定义:

data parent
结点信息 结点的双亲结点在数组中下标

如下,表示数组中元素的定义。

ArrNode[] treeArr = new ArrNode[TREE_SIZE];
class ArrNode {
	//数据部分
	Object data;
	//双亲结点位置
	int parent;
}

根结点没有父结点,所以第二个部分存储为 -1。
示例:一颗普通树 用双亲表示法,存储示意图
tree_parent

双亲表示法中,结点很容易找到父结点。但如果要找孩子结点,则需要遍历后才能找到。

孩子表示法

孩子表示法,采用数组+单链表的存储方式。
数组部分存储了结点的值,以及指向第一个孩子结点的指针。单链表存储的是某个结点的所有孩子结点,从左到右。所以N个结点,即数组大小为N,有N个链表。
如下,表示数组中元素定义,以及链表中元素定义。
数组元素定义:

data firstChildNode
结点信息 指向第一个孩子结点指针

链表中元素定义:

child next
孩子结点在数组中的下标 指向下个孩子结点的指针
ArrNode[] treeArr = new ArrNode[TREE_SIZE];

//链表中存储的孩子结点定义
class ChildNode {
	//孩子结点对应的在数组中存储的下标值
	int child;
	//下个孩子结点
	ChildNode next;
}

//数组中存储元素定义
class ArrNode {
	//数据部分
	Object data;
	//指向第一个孩子结点指针(引用)
	ChildNode firstChildNode;
}

如果是叶子结点(即没有孩子结点),链表为空。
示例:一颗普通树 用孩子表示法,存储示意图
tree_child

孩子表示法中,结点很容易找到孩子结点。但如果要找双亲结点,则需要遍历后才能找到。

提示:双亲结点和孩子结点都有明显的缺陷,但我们也可以将他们结合起来。即在孩子表示法基础上,数组元素定义中增加双亲位置的指针(即双亲表示法中的parent定义)。这种被称作“双亲孩子表示法”
数组元素定义:

data parent firstChildNode
结点信息 结点的双亲结点在数组中下标 指向第一个孩子结点指针

链表中元素定义:

child next
孩子结点在数组中的下标 指向下个孩子结点的指针

孩子兄弟表示法

孩子兄弟表示法,采用链表的存储方式。
通过孩子结点和兄弟结点来表示。

data firstChild firstBrother
结点信息 第一个孩子结点的指针(左孩子) 第一个兄弟结点的指针(右兄弟)
//结点定义
class TreeNode {
	Object data;
	TreeNode firstChild;
	TreeNode firstBrother;
}

示例:一颗普通树 用孩子兄弟表示法,存储示意图
tree_child_brother

树、森林与二叉树之间的转换

上面的孩子兄弟表示法也能感受到,那就是普通树转换成了一个二叉树。

网上有很多关于树、森林与二叉树之间的转换。这里简单总结下。
---若有不对,请指出。

树、森林转换成二叉树

结合上面孩子兄弟表示方法理解。

其实树 或者 森林 转换成二叉树是一样的。 因为树就是一个森林,单树森林。

转换规则简单是:
森林中第一颗树的根结点 作为 二叉树的根结点。然后所有结点 依次 遵循左孩子有兄弟即可。

下面简单示意说明下。
树(单树森林)转换二叉树

//单树                 二叉树
   A                     A
 / | \                  /
B  C  D    =======>    B    
|    /|\              / \
E   F G H            E   C
                          \
                           D
                          / 
                         F  
                          \
                           G
                            \
                             H

二叉树根结点即A(第一个棵树根结点),A的左孩子为B,右孩子为null(A是第一个树根结点,无兄弟)。然后看B,左孩子为E,右孩子为C(B、C、D兄弟结点)。再看E、C,依次类推即可将树转换成二叉树。

森林转换二叉树
同树转换成二叉树一样,将森林中的树看成兄弟即可。

//        森林                        二叉树
                                       A	
                                     /   \
   A       E     G                  /     \			
 / | \	   |	/ \                B       E
B  C  D    F   H   I  =======>     \     / \
               |                    C   F   G
               J                     \     / 
                                      D   H
                                         / \
                                        J   I

二叉树根结点即A(第一个棵树根结点),A的左孩子为B,右孩子为E(森林中的所有树看作兄弟结点)。然后看B,左孩子为null,右孩子为C(B、C、D兄弟结点),再看E,左孩子为F,右孩子为G。依次类推即可将森林转换成二叉树。

二叉树转换成树、森林

二叉树 转换成 树 或者 森林 也是一样的。 是上面树、森林转换成二叉树的逆向过程。

转换规则简单是:
二叉树的根结点即第一颗树的根结点。然后二叉树所有结点的 左孩子为(树或森林)结点的第一个孩子结点,右孩子为结点的兄弟结点。

下面简单示意说明下。
二叉树转换树(单树森林)

//二叉树                   单树
    A
   /
  B    
 / \                        A        
E   C                     / | \      
     \      =======>     B  C  D     
      D                  |    /|\    
     /                   E   F G H   
    F                    			
    \
     G
      \
       H

二叉树中A,有左孩子无右孩子。所以,该二叉树对应的是一棵树。A即树的根结点,左孩子B(二叉树中)即A的孩子结点(单树中)。看E、C(二叉树中),E为B左孩子,即E为B的孩子结点(孩子结点),C为B右孩子,即C为B的兄弟结点。依次类推即可。

二叉树转换森林
同理

//  二叉树                           森林
       A                                         
     /   \                     A       E     G   
    /     \                  / | \     |    / \	 
   B       E      =======>  B  C  D    F   H   I 
    \     / \                              |	 
     C   F   G                             J	 
      \     /                                    
       D   H                                     
          / \                                    
         J   I                                    

二叉树中A,有左孩子有右孩子。所以,该二叉树对应的不是一颗树。A即第一颗树的根结点,左孩子B(二叉树中)即A的孩子结点(第一颗树中);右孩子E(二叉树中)是A的兄弟,A是第一颗树的根结点,所以E为第二颗树根结点。看B的左右孩子(二叉树中),左孩子为空即B(第一颗树中)没有孩子结点,右孩子为C即是B的兄弟结点 在第一颗树中。依次类推即可。

posted @ 2020-06-16 21:42  流浪_归家  阅读(742)  评论(0编辑  收藏  举报