学习时间
2021-01-26
学习内容
二叉树
二叉树的定义
二叉树是n(n>=0)个结点的有限结合。在n=0时,称为空二叉树;在n>0时,集合可以理解为由一个根节点以及两棵互不相交的二叉树组成。我们称其为左子树和右子树。
所以我们可以这样理解二叉树:
二叉树是一个满足一下两个条件的树形结构
- 每个结点的度不大于2
- 每一棵子树的位置是确定的,不能随意改变
二叉树的性质
- 在二叉树的第i层上,最多有2^(i-1)个结点
- 深度为k的二叉树最多有2^k-1个结点
- 对任意一个二叉树,若终端结点数量为m,度为2的的结点数量为n,则有m=n+1
1、满二叉树:
深度为k,且含有2^k-1个结点的二叉树称为满二叉树。也就是说除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树。
2、完全二叉树:
深度为k,结点小于2^k-1的二叉树,当且仅当其所有结点与满二叉树一一对应时,称为完全二叉树。
图示:
二叉树的存储
顺序存储结构
对于满二叉树和完全二叉树来说,可以按照满二叉树结点的序号次序进行存储,即可以采用数组存储的方式进行存储。
可以知道数组中下标为i的结点的左孩子下表为2i,右孩子下标为2i+1,双亲的下标为i/2.
我们不难看出这样存储的特点是:可以很好的存储完全二叉树,但对一般的二叉树却不是很好存储。
我们可以采取这样一种策略:给普通的二叉树空位补一个空结点,将其补成一棵完全二叉树再进行存储。但是会带来存储空间的浪费。
链式存储结构
因为一个二叉树除了自身最多含有的两个孩子和自身的数据之外,没有其他数据了。我们就想到这样一种办法:
即给他设计三个域:
- 数据域
- 左孩子域
- 右孩子域
这样就形成了一种新的二叉树结构,我们也称之为二叉链表
图示:
不难看出:一个二叉树含有n个结点,则它的二叉链表中必含有2n个指针域,而仅有n-1个指针域指向他的孩子,其余n+1个都是指针域为空的链域。
二叉树的遍历
遍历操作可以理解为将二叉树的结点按一定的规律进行线性化的操作,将非线性化结构变成线性化的访问序列。
- 先序遍历
若二叉树为空,则空操作;
若二叉树不为空,则
先访问根节点
再先序遍历左子树
再先序遍历右子树 - 中序遍历
若二叉树为空,则空操作;
若二叉树不为空,则
先序遍历左子树
再访问根节点
再先序遍历右子树 - 后序遍历
若二叉树为空,则空操作;
若二叉树不为空,则
先序遍历左子树
再先序遍历右子树
再访问根节点 - 层次遍历
自根节点从上往下逐层遍历,每一层都是从左到右依次访问。
由遍历序列确定二叉树
两种遍历序列的组合 能否唯一确定二叉树
已知一棵树的两种序列,如何构造该二叉树
例:已知一棵树的先序和中序序列分别为:
A B C D E F G H I
B C A E D G H F I
试构造该二叉树
答:思路:
首先看先序序列:先序序列先看根,再看左子树、右子树,那么A就是该二叉树的根;然后,看中序序列,中序序列先看左子树,再看根,再看右子树,B C 在A 前头,而且A又是根,那么B C 就是属于左子树,D E F G H I 就是属于右子树。
其次看左子树:在先序序列中,左子树先访问的是B,然后再是C,那么,B 就是左子树的根;再看中序序列,左子树先访问的也是B,然后再是C,那么C就是B 的右子树
然后再看右子树:在先序序列中,右子树先访问的是D,那么D就是右子树的根,再看中序序列,先访问的是E,然后再是D,那么,E就是右子树下的左子树,F G H I 就是右子树下的右子树。
最后看右子树下的右子树(F G H I):在先序序列中,先访问的是F,那么F就是该分支树的根,再看中序序列,F前面是G H ,后面是I,则G H是分支树下的左子树,I是分支树下的右子树;又 (F G H ),(G H F)与(A B C),(B C A)一样,所以G 是分支根,H 是其右子树。
我们不难看出:看能否还原二叉树,就是看能否连续的找到根节点。
所以,由先序和后序序列不能确定一棵二叉树。
线索二叉树
在线索二叉树中,为了正确区分左右孩子的指针和指向前驱后继的指针,我们选择将结点结构改为5个域。
结构如下:
LChild—Ltag—Data—Rtag—RChild
其中:
- 若结点有左子树,则LChild域仍指向其左孩子;否则,LChild域指向其直接前驱结点
- 若结点有右子树,则RChild域仍指向其左孩子;否则,RChild域指向其直接后继结点
- Ltag=0,LChild域指向结点的左孩子;Ltag=1,LChild域指向结点的遍历前驱
- Rtag=0,RChild域指向结点的右孩子;Rtag=1,RChild域指向结点的遍历后继
线索二叉树的遍历如图所示: