树的概念和定义

前言

图1 树

上物,谓之树焉


基本概念

树是n(n≥0)个结点的有限集合T(Tree)。当n=0时,称为空树(其也是树);当n>0时, 该集合满足如下条件:

  • 其中必有一个称为根(root)的特定结点,它没有直接前驱,但有零个或多个直接后继。
  • 其余n-1个结点可以划分成m(m≥0)个互不相交的有限集T1,T2,T3,…,Tm,其中Ti又是一棵树,称为根root的子树。 每棵子树的根结点有且仅有一个直接前驱,但有零个或多个直接后继。

知识点

  • 结点:包含一个数据元素及若干指向其它结点的分支信息。
  • 结点的度:一个结点的子树个数称为此结点的度。
  • 叶结点:度为0的结点,即无后继的结点,也称为终端结点。
  • 分支结点:度不为0的结点,也称为非终端结点。
  • 孩子结点:一个结点的直接后继称为该结点的孩子结点。
  • 双亲结点:一个结点的直接前驱称为该结点的双亲结点。
  • 兄弟结点:同一双亲结点的孩子结点之间互称兄弟结点。
  • 祖先结点:一个结点的祖先结点是指从根结点到该结点的路径上的所有结点。在图1中,结点K的祖先是A、B、E。
  • 子孙结点:一个结点的直接后继和间接后继称为该结点的子孙结点。在图1中,结点D的子孙是H、I、 J、 M。
  • 树的度: 树中所有结点的度的最大值。
  • 结点的层次:从根结点开始定义,根结点的层次为1,根的直接后继的层次为2,依此类推。
  • 树的高度(深度): 树中所有结点的层次的最大值。
  • 有序树:在树T中,如果各子树Ti之间是有先后次序的,则称为有序树。
  • 森林: m(m≥0)棵互不相交的树的集合。将一棵非空树的根结点删去,树就变成一个森林;反之,给森林增加一个统一的根结点,森林就变成一棵树。

二叉树

二叉树的定义

定义:我们把满足以下两个条件的树形结构叫做二叉树(Binary Tree):

  • 每个结点的度都不大于2;
  • 每个结点的孩子结点次序不能任意颠倒。

由此定义可以看出,一个二叉树中的每个结点只能含有0、 1或2个孩子(条件一),而且每个孩子有左右之分(条件二)。我们把位于左边的孩子叫做左孩子,位于右边的孩子叫做右孩子。

二叉树的基本形态

由二叉树的定义我们可知,二叉树应有以下五种基本形态(注意是左右子树):
二叉树的基本形态

二叉树的性质


二叉树的性质1

在二叉树的第i层上至多有 2i-1 个结点(i≥1)。

证明

采用数学归纳法证明。

  • 归纳基础:当i=1时,整个二叉树只有一根结点,此时2i-1=20=1,结论成立。
  • 归纳假设:假设i=k时结论成立,即第k层上结点总数最多为2k-1个。

现证明当i=k+1时, 结论成立:

因为二叉树中每个结点的度最大为2,则第k+1层的结点总数最多为第k层上结点最大数的2倍,即2×2k-1=2(k+1)-1,故结论成立。


二叉树的性质2

深度为k的二叉树至多有2k-1个结点(k≥1)。

证明

因为深度为k的二叉树,其结点总数的最大值是将二叉树每层上结点的最大值相加,所以深度为k的二叉树的结点总数至多为

故结论成立。


二叉树的性质3

对任意一棵二叉树T,若终端结点数为n0,而其度数为2的结点数为n2,则n0=n2+1。

证明

设二叉树中结点总数为n, n1为二叉树中度为1的结点总数。
因为二叉树中所有结点的度小于等于2,所以有

n=n0+n2+n2

设二叉树中分支数目为B(其实就是边数), 因为除根结点外, 每个结点均对应一个进入它的分支,所以有

n=B+1

又因为二叉树中的分支都是由度为1和度为2的结点发出, 所以分支数目为

B=n1+2n2

整理上述两式可得到

n=B+1=n1+2n2+1

将n=n0+n11+n2代入上式,得出n0+n1+n2=n1+2n2+1,整理后得n0=n2+1,故结论成立。


满二叉树

深度为k且有2k-1个结点的二叉树。在满二叉树中,每层结点都是满的,即每层结点都具有最大结点数。 图3(a)所示的二叉树,即为一棵满二叉树。
满二叉树的顺序表示,即从二叉树的根开始, 层间从上到下, 层内从左到右,逐层进行编号(1, 2, …, n)。例如图3(a)所示的满二叉树的顺序表示为(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)。

图3 满二叉树与完全二叉树


二叉树的性质4

具有n个结点的完全二叉树的深度为int(log2n)+1。

证明

假设n个结点的完全二叉树的深度为k,根据性质2可知,k-1层满二叉树的结点总数为

n1=2k-1-1

k层满二叉树的结点总数为

n2=2k-1

显然有n1<n≤n2,进一步可以推出n1+1≤n<n2+1。
将n1=2k-1-1和n2=2k-1代入上式,可得2k-1≤n<2k,即k-1≤log2n<k
因为k是整数,所以k-1=int(log2n),k=int(log2n)+1, 故结论成立。


二叉树的性质5

对于具有n个结点的完全二叉树, 如果按照从上到 下和从左到右的顺序对二叉树中的所有结点从1开始顺序编号, 则对于任意的序号为i的结点有:

(1) 如i=1,则序号为i的结点是根结点, 无双亲结点; 如i>1, 则序号为i的结点的双亲结点序号为int(i/2)。

(2) 如2×i>n,则序号为i的结点无左孩子;如2×i≤n,则序号为i的结点的左孩子结点的序号为2×i。

(3) 如2×i+1>n,则序号为i的结点无右孩子;如2×i+1≤n, 则序号为i的结点的右孩子结点的序号为2×i+1。

证明

可以用归纳法证明其中的(2)和(3):

当i=1时,由完全二叉树的定义知,如果2×i=2≤n,说明二叉树中存在两个或两个以上的结点,所以其左孩子存在且序号为2; 反之,如果2>n,说明二叉树中不存在序号为2的结点,其左孩子不存在。同理,如果2×i+1=3≤n, 说明其右孩子存在且序号为3;如果3>n,则二叉树中不存在序号为3的结点, 其右孩子不存在。

假设对于序号为j(1≤j≤i)的结点,当2×j≤n时,其左孩子存在且序号为2×j,当2×j>n 时,其左孩子不存在;当2×j+1≤n时, 其右孩子存在且序号为2×j+1,当2×j+1>n时,其右孩子不存在。

当i=j+1时,根据完全二叉树的定义, 若其左孩子存在, 则其左孩子结点的序号一定等于序号为j的结点的右孩子的序号加1, 即其左孩子结点的序号等于 (2×j+1)+1=2(j+1)=2×i, 且有2×i≤n;如果2×i>n, 则左孩子不存在。 若右孩子结点存在,则其右孩子结点的序号应等于其左孩子结点的序号加1,即右孩子结点的序号为2×i+1,且有2×i+1≤n;如果2×i+1>n,则右孩子不存在。

故(2)和(3)得证。

由(2)和(3)我们可以很容易证明(1)。

当i=1时, 显然该结点为根结点,无双亲结点。当i>1时,设序号为i的结点的双亲结点的序号为m,如果序号为i的结点是其双亲结点的左孩子,根据(2)有i=2×m,即m=i/2; 如果序号为i的结点是其双亲结点的右孩子,根据(3)有i=2×m+1, 即m=(i-1)/2=i/2-1/2,综合这两种情况,可以得到,当i>1时, 其双亲结点的序号等于int(i/2)。

证毕。


二叉树的存储结构

二叉树的结构是非线性的, 每一结点最多可有两个后继。

二叉树的存储结构有两种: 顺序存储结构和链式存储结构。

顺序存储结构

图4 二叉树与顺序存储结构

图5  单支二叉树与其顺序存储结构

链式存储结构

对于任意的二叉树来说,每个结点最多只有两个孩子,一个双亲结点。我们可以设计每个结点至少包括三个域:数据域、 左孩子域和右孩子域:

其中,LChild域指向该结点的左孩子,Data域记录该结点的信息,RChild域指向该结点的右孩子。

用C++可以这样声明二叉树的二叉链表结点的结构:

有时,为了便于找到父结点,可以增加一个Parent域, Parent域指向该结点的父结点。 该结点结构如下:

图例

图6 二叉树和二叉链表

二叉树的性质6

若一个二叉树含有n个结点,则它的二叉链表中必含有2n个指针域, 其中必有n+1个空的链域。

证明

分支数目B=n-1,即非空的链域有n-1个,故空链域有2n-(n-1)=n+1个。

不同的存储结构实现二叉树的操作也不同。如要找某个结点的父结点,在三叉链表中很容易实现;在二叉链表中则需从根指针出发一一查找。可见,在具体应用中,需要根据二叉树的形态和需要进行的操作来决定二叉树的存储结构。


二叉树的遍历

我们用L、D、R分别表示遍历左子树、访问根结点、 遍历右子树, 那么对二叉树的遍历顺序就可以有六种方式:
  • 访问根,遍历左子树,遍历右子树(记做DLR)。
  • 访问根,遍历右子树,遍历左子树(记做DRL)。
  • 遍历左子树,访问根,遍历右子树(记做LDR)。
  • 遍历左子树,遍历右子树,访问根(记做LRD)。
  • 遍历右子树,访问根,遍历左子树(记做RDL)。
  • 遍历右子树,遍历左子树,访问根(记做RLD)。

注意:先序、中序、后序遍历是递归定义的, 即在其子树中也按上述规律进行遍历。

先序遍历(DLR)

若二叉树为空,则空操作,否则依次执行如下3个操作:

  • 访问根结点;
  • 按先序遍历左子树;
  • 按先序遍历右子树。

中序遍历(LDR)

若二叉树为空,则空操作,否则依次执行如下3个操作:

  • 按中序遍历左子树;
  • 访问根结点;
  • 按中序遍历右子树。

后序遍历(LRD)操作过程:

若二叉树为空,则空操作,否则依次执行如下3个操作:

  • 按后序遍历左子树;
  • 按后序遍历右子树;
  • 访问根结点。

图8 二叉树

先序遍历: A、 B、 D、 F、 G、 C、 E、 H 。

中序遍历: B、 F、 D、 G、 A、 C、 E、 H 。

后序遍历: F、 G、 D、 B、 H、 E、 C、 A 。

中序遍历二叉树的递归过程

最早提出遍历问题是对存储在计算机中的表达式求值。例如:(a+b*c)-d/e。该表达式用二叉树表示如图6.9所示。当我们对此二叉树进行先序、中序、后序遍历时,便可获得表达式的前缀、 中缀、 后缀书写形式:

前缀: -+a*bc/de

中缀: a+b*c-d/e

后缀: abc*+de/-

其中中缀形式是算术表达式的通常形式,只是没有括号。 前缀表达式称为波兰表达式。后缀表达式被称作逆波兰表达式。 在计算机内, 使用后缀表达式易于求值。

图9 算术式的二叉树表示

其中中缀形式是算术表达式的通常形式,只是没有括号。 前缀表达式称为波兰表达式。后缀表达式被称作逆波兰表达式。 在计算机内, 使用后缀表达式易于求值。

注意: 通过一棵二叉树可以得到3种遍历次序,那编码可逆吗?也就是通过1种遍历次序能构造唯一的二叉树吗?答案肯定是不能的!而且通过2种遍历次序也不完全能构造唯一的二叉树(2种次序中必须要包含中序遍历才能构造唯一的二叉树)

推荐博客


字典树

字典树、又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。

字典树与字典很相似,当你要查一个单词是不是在字典树中,首先看单词的第一个字母是不是在字典的第一层,如果不在,说明字典树里没有该单词,如果有就在该字母的孩子节点里找是不是有单词的第二个字母,没有就说明没有该单词,有的话用同样的方法继续查找。字典树不仅可以用来储存字母,也可以储存数字等其它数据。

字典树


线段树

线段树(Segment Tree)是一种二叉搜索树,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。

对于线段树中的每一个非叶子结点[a,b],它的左子树表示的区间为[a,(a+b)/2],右子树表示的区间为[(a+b)/2+1,b]。因此线段树是平衡二叉树。叶结点数目为N,即整个线段区间的长度。

使用线段树可以快速的查找某一个结点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,因此有时需要离散化让空间压缩。

线段树


平衡二叉搜索树

平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

平衡二叉搜索树

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值