一、关于树的几个基本概念
结点:一个数据元素及若干指向其子树的分支
结点的度:结点所拥有的子树的个数称为该结点的度
树的度:树中个结点的度的最大值称为该树的度
叶子结点:度为0的结点称为叶子结点
非叶子结点:度不为0的结点称为非叶子结点(分支结点)。根结点外的分支结点又称内部结点。
孩子结点:一个结点的子树的根
双亲结点\父结点
兄弟结点:拥有同一父结点的所有结点
层次:根结点的层次为0(或1),其余结点的层次为其父结点层次加1
堂兄弟结点:双亲结点在同一层的结点
层次路径:从根结点开始,到达某结点所经过的所有结点称为p的层次路径(有且仅有一条)
祖先:层次路径上不包括p的所有结点
树的深度(高度):树中结点的最大层次值
森林:若干棵互不相交的树的集合。将一棵树的根结点删除,剩余子树构成了森林。
· 树的三种表示形式
二、二叉树
· 二叉树可以为空集合
· 二叉树不是树的特殊情况,它们是两个概念:① 与无序树不同... ② 与度为2的有序树不同:在二叉树中,即使是一个孩子也有左右之分
· 满二叉树:在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶结点都在同一层上,这样的一棵二叉树称作 满二叉树。
满二叉树的结点编号是固定的:
· 完全二叉树:一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。
完全二叉树的特点:叶结点只能出现在最下层和次下层,且最下层的叶结点集中在树的左部。
二叉树的一个应用:表达式树
· 二叉树的几个重要性质
① 二叉树的第i层上至多有2^(i-1)个结点
② 深度为k的二叉树最多有2^k - 1个结点
③ 对任何一棵二叉树,如果叶结点数为x,度为2的结点数为y,则有 x = y + 1
④ 具有n个结点的二叉树其深度为[log2n + 1]向下取整
⑤ 对一棵有n个结点的完全二叉树,按从上到下,从左到右的顺序编号:
1)若i=1,则为根结点;否则,其父结点为[i/2]
2)若2*i > n,则其为叶结点;否则其左孩子编号为2*i
3)若2*i + 1 > n,则其无右孩子;否则其右孩子编号为2*i + 1
运用性质与公式求解题目
三、二叉树的存储
1、顺序存储
· 对于满二叉树或者完全二叉树:可以采用顺序存储的结构。从上自下,从左自右,结点在二叉树中的位置与在数组中的位置具有一一对应的关系。
对于一般的二叉树,若也想采用顺序存储的结构,则需要添加一些空结点,构造完全二叉树,再进行储存。
2、链式存储
每个结点的元素:数据、左指针、右指针
四、二叉树的遍历
1)先序遍历:中--左--右
2)中序遍历:左--中--右
3)后序遍历:左--右--中
4)层次遍历:从上自下,从左自右。可以使用队列进行遍历
五、二叉树的遍历的实现方法
1、非递归实现
a、先序遍历:访问根结点,入栈右结点(若不为空),进左结点(若不为空)。若左结点为空,则出栈一个结点,继续访问操作。
过程图如下:
b、中序遍历:
过程图如下:
附上代码:
void BinaryTree<T>::InOrder(void (*visit) (BinTreeNode<T> *t))
{
stack<BinTreeNode<T>*> S;
BinTreeNode<T> *p = root;
do
{
while (p != NULL)
{
S.Push (p);
p = p->leftChild;
}
if (!S.IsEmpty())
{
S.Pop (p);
visit (p);
p = p->rightChild;
}
} while (p != NULL || !S.IsEmpty ());
}
c、后序遍历
过程图如下:
出栈若标记为L,则改标记为R,然后入栈,接着访问右右孩子;若标记为R,则直接访问改结点,不如再次入栈。
2、递归实现法
六、由遍历序列恢复二叉树
1、先序序列和中序序列确定一棵二叉树
直接看例题:
2、由后序序列和中序序列确定一棵二叉树
与1一样,根据后续序列确定根结点,然后在中序序列中分出左右子树,然后再在后序序列中分出左右子树非后序序列,不断循环。
例题:
·仅知道先序序列和后序序列则无法唯一确定一棵二叉树
七、线索二叉树
八、树
1、满k叉树
满k叉树的性质:
· 第h 层上的结点都是叶结点,其余各层上每个结点都有 k 棵非空子树,如果按层次自顶向下,同一层自左向右,顺序从 0开始对全部结点进行编号:
第i 层的结点个数是ki个 ( i= 0, 1, ..., h ) ;
编号为i 的结点的父结点(若存在)的编号是 :(i - 1) / k 向下取整
2、树的几种存储方法
a、孩子表示法
b、双亲表示法
c、双亲孩子表示法
d、孩子兄弟表示法
九、树和森林的遍历
1、树的遍历
(1)先根遍历:先访问根结点;然后按照从左到右的顺序访问根结点的每一棵子树。
(2)后根遍历:按从左到右访问根的每一棵子树;然后访问根结点。
(3)层次遍历:从上到下,从左到右。
2、森林的遍历
(1)先根遍历:若森林为空,返回;否则访问F的第一棵树的根结点;先根次序遍历第一棵树的子树森林;先根遍历其它树组成的森林。
(2)后根遍历:若森林为空,返回;否则后根遍历第一棵树的子树森林;后根遍历其它树组成的森林;访问F的第一棵树的根结点。
(3)层次遍历:若森林为空,返回;否则依次遍历各棵树的根接待你;依次遍历各棵树根结点的所有子女;依次遍历这些子女结点的子女结点。
十、树、森林与二叉树的转换
1、树转化为二叉树:
(1) 树中所有相邻兄弟之间加一条连线。
(2) 对树中的每个结点,只保留它与第一个孩子结点之间的连线,删去
它与其它孩子结点之间的连线。
(3) 以树的根结点为轴心,将整棵树顺时针转动一定的角度,使之结构层次分明。
2、森林转化为二叉树
(1) 将森林中的每棵树转换成相应的二叉树。
(2) 第一棵二叉树不动,从第二棵二叉树开始,依次把后一棵二叉树的根结点作为前一棵二叉树根结点的右孩子,当所有二叉树连起来后,此时所得到的二叉树就是由森林转换得到的二叉树。
3、二叉树转化为树和森林
(1)若某结点是其双亲的左孩子,则把该结点的右孩子、右孩子的右孩子......都与该结点的双亲结点用线连起来;
(2)删去原二叉树中所有的双亲结点与右孩子结点的连线;
(3) 整理由(1)、(2)两步所得到的树或森林,使之结构层次分明。
十一、哈夫曼树及其应用
1、二叉树带权路径长度:设二叉树具有n个带权值的叶结点,那么从根结点到各个叶结点的路径长度与相应结点权值的乘积之和叫做二叉树的带权路径长度。
2、在给定一组具有确定权值的叶结点,可以构造出不同的带权二叉树。
如下图:
3、哈夫曼树的定义
最优二叉树,也称哈夫曼(Haffman)树,是指对于一组带有确定权值的叶结点,构造的具有最小带权路径长度的二叉树。
4、哈夫曼树的构造思路
(1) 由给定的n个权值{W1,W2,...,Wn}构造n棵只有一个叶结点的二叉树,从而得到一个二叉树的集合F={T ,T ,...,T };
12n
(2) 在F中选取根结点的权值最小和次小的两棵二叉树作为左、右子树构造一棵新的二叉树,这棵新的二叉树根结点的权值为其左、右子树根结点权值之和;
(3) 在集合F中删除作为左、右子树的两棵二叉树,并将新建立的二叉树加入到集合F中;
(4) 重复(2)、(3)两步,当F中只剩下一棵二叉树时,这棵二叉树便是所要建立的哈夫曼树。
如下图:
5、哈夫曼编码
如ABCADAB字符串,给每个字符一个不等长的01编码,如何安排,是字符串对应的二进制编码最短?
注:使用哈夫曼编码不会出现二义性问题,因为任何一个字符的编码都不是另一个字符编码的前缀。
例:
本文详细介绍了树的基本概念,包括结点、度、叶结点等,以及二叉树的特性,如满二叉树、完全二叉树的定义和性质。此外,还探讨了二叉树的顺序存储、链式存储、遍历方法(先序、中序、后序、层次遍历)以及二叉树的遍历实现。内容涵盖了从树的存储结构到遍历算法,为理解和操作树型数据结构提供了全面的知识。
5万+

被折叠的 条评论
为什么被折叠?



