树的基本概念
节点的度:节点的儿子数
树的度:Max{节点的度}
节点的高度:节点到各叶节点的最大路径长度
树的高度:根节点的高度
节点的深度(层数):根节点到该节点的路径长度
树的遍历
·前序遍历:根左右(x,Tl,Tr)
·中序遍历:左根右(Tl,x,Tr)
·后序遍历:左右根(Tl,Tr,x)
树的表示法
1.父节点数组表示法
(寻找父节点O(1),寻找儿子节点O(n))
2.儿子链表表示法
(为克服找父节点不方便,可牺牲空间换时间:)
3.左儿子右兄弟表示法
(通过左儿子右兄弟表示法将一个树存储方式变化为二叉树形态)
(可将森林用类似的方法变化为二叉树(不同的树根节点用右兄弟的指针连接))
二叉树基本概念
·n个节点的二叉树 高度h的取值范围是 [logn向下取整,n-1]
·高度为h的二叉树 节点数n的取值范围是 [h+1,2^(h+1)-1]
·满二叉树:高度为h且有2^(h+1)-1个节点
·近似满二叉树:除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边。
对每个结点i,满足:
i
/ \
2i 2i+1
因此可用数组存储(节点间关系显见),若为非近似满二叉树想要这样存储,没有该节点的位置可用空占位(牺牲空间)。
·节点数(设度为i的节点数为ni)
N = n0+n1+n2 = n0×0+n1×1+n2×2 +1 ( 节点数 = 分枝数+1 )
可得结论 =>
① n0 = n2 + 1
② N = 2×n0 + n1 - 1 = 2×n2 + n1 + 1
在哈夫曼树中n1 = 0,则有N = 2×n0 - 1 = 2×n2 + 1
·含有n个结点二叉树的不同形态数Bn
Bn = ∑(Bl × Bn-l-1) (左子树+右子树)
=>卡特兰数Bn = 1/(n+1) × C(2n,n)
·二叉树与树
①二叉树是一棵度不超过2的树。(错误,二叉树的儿子节点有左右之分)
②二叉树是一棵读不超过2的有序数。(错误,当只有1个儿子节点时二叉树也有左右之分)
ADT二叉树
·支持的运算
1.BinaryInit():创建一棵空二叉树
2.BinaryEmpty(T):判断二叉树T是否为空
3.Root(T):返回根节点标号
4.MakeTree(x,T,L,R):以x为根节点,L、R为左右子树构建新二叉树T
5.BreakTree(T,L,R):将T拆分为根节点元素、左右子树三个部分
6.PreOrder(T):前序遍历
7.InOrder(T):中序遍历
8.PostOrder(T):后序遍历
/*6、7、8在书上写的函数参数是(visit,T),没解释visit是什么,然后9,10,11是输出前中后序列表,参数只有T。博客这里就使用6,7,8函数名字当它作用就是输出列表了,略去了书上的9,10,11。*/
9.Delete(T):删除二叉树
10.Height(T):二叉树高度
11.Size(T):二叉树结点数
二叉树的实现
1.顺序存储结构
(从树根起,从上往下逐层编号存在数组里。适用于满二叉树,若非满二叉树,则用0占空。)
以该种存储方式得到的性质:
1.当且仅当i = 1时为根节点。
2.不为1时,父节点为i/2(向下取整)
3.左儿子为2i
4.右儿子为2i+1
5.i为奇数且不为1时,左兄弟为i-1
6.i为偶数时,右兄弟为i+1
2.结点度表示法
(将所有结点以后序列表排列,给每个结点附加一个0~3的整数表示状态,0表示叶节点,1表示有一个左儿子,2表示有一个右儿子,3表示有两个儿子。)
得到性质:
1. i-1 为右儿子结点
2.必然有左儿子在 i 前,父节点在 i 后
3.用指针实现
线索二叉树
(在每个结点中增加指向在某种遍历下其前驱和后继结点的指针)
线索:所引入的非空指针称为线索。 线索二叉树:加上了线索的二叉树称为线索二叉树。 线索标志位:为了区分一个结点的指针是指向其儿子结点的
指针,还是指向其前驱或后继结点的线索,在每个结点中增 加2个位—leftThread、rightThread分别称为左、右线索标志位。
线索化:对一棵非线索二叉树以某种次序遍历使其变为一棵 线索二叉树的过程称为二叉树的线索化。二叉树线索化: 由于线索化的实质是将二叉树中的空指针改为指向其前 驱结点或后继结点的线索(并做上线索标志),而一个结
点的前驱或后继结点只有遍历才能知道,因此线索化的 过程是在对二叉树遍历的过程中修改空指针的过程。
为了记下遍历过程中访问结点的先后次序,可引入指针p 指引遍历,而引入指针pre跟踪p的前驱。首先将pre和p
初始化为遍历的第一结点。然后让p往遍历的方向走找 pre的后继。一旦找到,则它们互为前驱和后继,建立相
应线索。接着将p赋给pre,重复下去直到遍历结束。 二叉树的中序线索化 增加一个头结点,其LeftChild指针指向二叉树的根结
点,其RightChild指针指向中序遍历的最后一个结点。 而最后一个结点的RightChild指针指向头结点。这样一
来,就好象为二叉树建立了一个双向线索链表,既可从 中序遍历的第一个结点起进行中序的遍历;也可从中序
遍历的最后一个结点起进行逆中序的遍历。
在树的运算实现中常常用到递归。
如:
1.求二叉树叶结点数
2.求二叉树高度 H = Max{Hl,Hr} + 1
3.求二叉树结点数 N = Nl+Nr+1
伪代码:
if(!t) return 0;
l = Size(t->left)
r = Size(t->right)
return l+r+1;
思考:给定二叉树前中后序中的任意2个能否唯一确定该树?给出证明和设计算法确定树。
(转)下面是这个问题的证明与结论:
①给定二叉树结点的前序序列和对称序(中序)序列,可以唯一确定该二叉树。
证明:因为前序序列的第一个元素是根结点,该元素将二叉树中序序列分成两部分,左边(设1个元素)表示左子树,若左边无元素,则说明左子树为空;右边(设r个元素)是右子树,若为空,则右子树为空。根据前序遍历中’根-左子树-右子树’的顺序,则由从第二元素开始的1个结点序列和中序序列根左边的1个结点序列构造左子树,由前序序列最后r个元素序列与中序序列根右边的r个元素序列构造右子树。
②由中序序列和先序序列能唯一确定一棵二叉树,但是由先序序列和后序序列不能唯一确定一棵二叉树,因无法确定左右子树两部分。
反例:任何结点只有左子树的二叉树和任何结点只有右子树的二叉树,其前序序列相同,后序序列相同,但却是两棵不同的二叉树。
③已经说明由二叉树的前序序列和中序序列可以确定一棵二叉树,现在来证明由二叉树的中序序列和后序序列,也可以唯一确定一棵二叉树。
证明:
当n=1时,只有一个根结点,由中序序列和后序序列可以确定这棵二叉树。
设当n=m-1时结论成立,现证明当n=m时结论成立。
设中序序列为S1,S2,…,Sm,后序序列是P1,P2,…,Pm。因后序序列最后一个元素Pm是根,则在中序序列中可找到与Pm相等的结点(设二叉树中各结点互不相同)Si(1≤i≤m),因中序序列是由中序遍历而得,所以Si是根结点,S1,S2,…,Si-1是左子树的中序序列,而Si+1,Si+2,…,Sm是右子树的中序序列。
若i=1,则 S1是根,这时二叉树的左子树为空,右子树的结点数是m-1,则{S2,S3,…,Sm}和{P1,P2,…,Pm-1}可以唯一确定右子树,从而也确定了二叉树。
若i=m,则Sm是根,这时二叉树的右子树为空,左子树的结点数是m-1