【笔记】树

一、树的概念

1.树的定义

  一个结点x组成的集{x}是一棵树,这个结点x也是这棵树的根。
  假设x是一个结点, T1,T2,Tk 是K颗互不相交的树,可以构造一颗新树:令x为根,并由K(K 0)条边由x指向树 T1,T2,Tk 。这些边也叫做分支, T1,T2,Tk 称作根为x的树的子树。

  • 空集合也是树,称为空树。空树中没有结点。
  • 单个结点是一棵树,树根就是结点本身。
  • 若某树有多个结点,则每个结点都可以看成是根结点(要么是整个树的根结点,要么是某个子树的根结点)。

  在一棵树中,每个结点为其字数的根节点的前驱,而其子树的根结点就是其后继。

  • 在一棵树中,有且皆有一个结点没有前驱,这个节点就是树的根结点。
  • 除根结点外,其余每个结点有且仅有一个前驱。
  • 每个结点可以有任意多个后继。

2.树的相关术语

父结点、子结点、兄弟结点:每个结点的子树的根称为该结点的儿子(子结点),相应地该结点被称为子结点的父亲(父结点),具有同一父结点的结点称为兄弟结点。
路径:如果 n1,n2,nk 是树中的结点序列,并且 ni ni+1(1ik1) 的父亲,则结点序列 n1,n2,nk 称为 n1 ~ nk 的一条路径,而且路径长度就是该路径中的结点个数减1.显然,每个结点到自己的路长为0。
祖先与后代:如果从结点A到结点B有一条路径,则称A为B的祖先,B是A的后代。注意,任何一个结点既是它自己的祖先也是它自己的后代。
结点的度:一个结点的子树个数称为该结点的度,或叫做结点的元。
叶结点与分枝结点:度为0的结点,称为叶结点或终结结点,其余的结点叫分枝结点、非叶结点或非终结结点。
树的度:指该树中结点的最大度数。
结点的层:树是一种层次结构,每个结点都处在一定的层次上。从根算起,根为第一层,若某个结点在第L层上,则此结点的儿子在第L+1层。结点的层就是从根到该结点的路长加1。
结点的高:从一个结点的最大路长加1称为该结点的高。
树的高:树的高定义为根节点的高,即该棵树所有结点中最大的层号。
树的深度:一棵树中结点的最大层数称为树的深度。
有序树与无序树:若树中的各结点的子树(兄弟结点)是按一定次序从左向右安排的,则称为有序树,否则为无序树。
森林:森林是m( m0 )颗互不相交的树的集合。如果去掉树的根节点,就得到一个森林。

  • 结点的顺序
      下面把兄弟结点之间的自左而右顺序加以推广。如果a是b的兄弟,且a在b之左,则称a的所有后代在b的所有后代之左。
      有一个简单的规则可用来求给结点n其左边与右边的所有结点。即从根到n画一条路径,则这条路径以左的所有结点以及这些结点的所有后代都在n的左边;而这条路径以右的所有结点以及这些结点的所有后代都在n的右边。

3.树的表示

  树的表示方法有很多,常用的方法是用括号:先将根节点放入一对圆括号中, 然后把它的子树按照有左至右的顺序放入括号中,而对子树也采用同样的方法处理;同层子树与它的根节点用圆括号括起来,同层子树之间用逗号隔开,最后用闭括号括起来。


这里写图片描述

如上图的树可表示为(A(B(E((K),(L)),(F)),C(G),D(H(M)),(I),(J))))。

  详情参见树的表示


二、二叉树

1.二叉树的概念

  在树的应用中,二叉树是最简单的一种形式,而二叉树又特别重要,这是因为处理树的许多算法应用到二叉树时变得非常简单,而任意的树又可以方便地转换成对应的二叉树。因此,只需要定义二叉树的算法,容纳后将其他树转换为二叉树,即可方便地对所有的树进行操作。所以说,二叉树是所有书结构的基础。

  • 二叉树
      二叉树是有限个结点的集合,这个集合或者是空集,或者由一个根结点和两颗不想叫的二叉树组成, 其中的一棵叫做根的左子树,另一颗叫做根的右子树。

注意:虽然树和二叉树之间有许多联系,但是二叉树不是作为树的特殊情形来定义的。

  二叉树有5种基本形态:

  • 仅有根节点
  • 仅有左子树
  • 仅有右子树
  • 有左右子树


这里写图片描述

  二叉树和树的两个主要差别如下:

  • 树中结点的最大度数没有限制,而二叉树结点的最大度数为2。
  • 树的结点无左、右之分,而二叉树的结点有左、右之分。
  • 满二叉树
      满二叉树是高为k且有 2k1 个结点的二叉树。

  • 完全二叉树
      完全二叉树是具有下属性质的二叉树(设二叉树的高为k):

  • 所有叶结点都出现在k或k-1层。
  • k-1层的所有叶结点都在非终结结点的右边。
  • 除k-1层的最右非终结结点可能有一个(只能是左分支)或两个分支之外,其余非终结结点都有两个分支。

注:满二叉树肯定是完全二叉树,而完全二叉树不一定是满二叉树。

2.二叉树的性质

  根据二叉树的定义,可得知其具有一下性质:

  1. 在二叉树中,第i层的结点总数最多为2i-1。
  2. 深度为k的二叉树最多有2k-1个结点( k1 ),最少有k个结点。
  3. 对于一颗二叉树,如果其叶结点数为 n0 ,而度为2的结点总数为 n2 ,则 n0=n2+1
  4. 具有n个结点的完全二叉树的深度k为: k=[log2n]+1 .
  5. 有n个结点的完全二叉树各结点如果用顺序方式存储,对任意结点i,有如下关系:
    • 如果i!=1,则其父结点的编号为i/2。
    • 如果2*i n,则其左子树根节点的编号为2*i;若2*i n,则无左子树;
    • 如果2*i+1 n,则其右子树根节点编号为2*i+1;若2*i+1 n,则无右子树。

3.二叉树的存储

  二叉树通常可采用三类存储结构:顺序存储结构、链式存储结构和游标表示结构。

  • 顺序存储结构
      与线性表的顺序存储类似,二叉树的顺序存储结构一般也有一个一维数组来构成,二叉树上的结点按照某种贵的次序逐个保存到数组的各个单元中。
      二叉树顺序存储结构的数据定义如下:
define MAXSIZE 100   //最大结点数
typedef int DATA;    //元素类型
tpedef int DATA SeqBinTree[MAXSIZE];
SeqBinTree SBT;    //定义保存二叉树数组

注:要使用一维数组保存二叉树的结点, 关键在于定义结点的存储次序,要求这种次序应该反映结点之间的逻辑关系(父子关系),否则二叉树的基本运算就难以实现。

  对于非完全二叉树为了能使结点与数组序号有对应的关系,一般采取的方法是:将非完全二叉树转换为完全二叉树,将左侧缺少的结点虚设为无数据的结点(这里假设以符号“#”来表示)。


这里写图片描述

  将上图所示的完全二叉树按顺序保存到一维数组中,得到如下图所示的一位数组,这样每个结点的序号又与数组的序号有了对应关系。


这里写图片描述

  • 链式存储结构
      由于二叉树的顺序存储结构会造成存储空间的浪费,因此大多数情况下二叉树都采用链式存储结构。使用链式存储接哦股非常符合二叉树的逻辑结构,一个结点可以由节点元素和两个分别指向左、右子树的指针组成,这种节点结构称为二叉链表结构。有时为了方便查找父节点,还可增加一个指向父结点的指针,这种结构称为三叉链表结构。

  二叉链表结构

typedef struct ChainTree
{
    DATA data;//元素数据
    struct ChainTree *left;//左子树结点指针
    struct ChainTree *right;//右子树结点指针
}ChainTreeType;
ChainTreeType *root=NULL;//定义二叉树根节点指针

  三叉链表结构:

typedef struct ChainTree
{
    DATA data;//元素数据
    struct ChainTree *left;左子树结点指针
    struct ChainTree *right;//右子树结点指针
    struct ChainTree *parent;//父结点指针
}ChainTreeType;
ChainTreeType *root=NULL;//定义二叉树根节点指针

4.二叉树的实现

  源码参见二叉树的实现

5.二叉树的遍历

  遍历是对树的一种基本运算,所谓遍历二叉树,就是按照一定的规则和顺序走遍二叉树的所有子树。使每一个结点都被访问一次,而且只被访问一次。
  对于具有左右子树的二叉树,其中D表示根结点,L表示左子树,R表示右子树,对其遍历有三种方式:


这里写图片描述

  • 按层遍历:对于二叉树的按层遍历,不能方便地使用递归算法来编写代码,而是使用一个循环队列来进行处理。首先将第1层(根节点)进入队列,再将第1结点根结的左右子树(第2层)进入队列,……就这样循环处理,就可以逐层遍历。


这里写图片描述

  • 先序遍历(DLR):称为先根次序遍历,即先访问根节点,再按先序遍历左子树,最后按先序遍历右子树。

  • 中序遍历(LDR):称为中根次序遍历,即先按中序遍历左子树,再访问根节点,最后按中序遍历右子树。

  • 后序遍历(LRD):称为后根次数遍历,即先按后序遍历左子树,再按后序遍历右子树,最后再访问根节点。

  源码参见二叉树的遍历


6.线索二叉树

  详情参见线索二叉树

三、二叉树的应用

1.堆及其实现

  详情参见堆及其实现

2.遍历二叉树的应用

  详情参见遍历二叉树的应用

四、树、森林与二叉树的关系

  详情参见树、森林与二叉树的转换与应用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值