32、树和二叉树

1、树


          树是一种非常常用的数据结构,树与前面介绍的线性表、栈、队列等线性结构不同,树是一种非线性结构。一棵树只能有一个根节点,如果一棵树有了多个根节点,那么它就已经不再是一棵树了,而是多棵树的集合,称为森林。

   树的递归特性:一棵树由根和若干棵子树组成,而每棵子树又由若干棵更小的子树组成。

1.1、父节点表示法

   树中除根节点之外的每个节点都有一个父节点,为了记录树中节点与节点之间的父子关系,可以为每个节点增加一个parent域,用以记录该节点的父节点。具体操作:用一个节点数组来保存树里的每个节点,并让每个节点记录其父节点在数组中的索引即可。

   父节点表示法的特点是,每个节点都可以快速找到它的父节点,但如果要找某个节点的所有子节点就比较麻烦,程序要遍历整个节点数组。

1.2、子节点表示法

   让父节点“记住”它的所有的子节点,可能需要记住多个子节点,因此必须采用“子节点链”表示法。

   子节点链表示法的特点是,每个节点都可以快速找到它的所有子节点,但如果要找某个节点的父节点则比较麻烦,程序要遍历整个节点数组。


2、二叉树


   二叉树是树的特例,每个节点最多只有两个子树的有序树。左边子树称“左子树”(left subtree),右边子树称“右子树”(right subtree)。

   满二叉树:树深度为k,包含节点数为2^k-1。每层节点数都是最大节点数,即各层节点数分别为1,2,4,8,16,……

   完全二叉树:二叉树除最后一层外,其余层的所有节点都是满的,并且最后一层或者是满的,或者仅在右边缺少若干连续的节点。

2.1、二叉树的性质

(1)二叉树第i层上的节点数目最多为2^(k-1)(i>=1)。

(2)深度为k的满二叉树包含的节点数为公比为2的等比数列的前k项总和,即2^k-1。

(3)在任何一棵二叉树中,如果其叶子节点的数量为n0,度为2的子节点数量为n2,则n0=n2+1。

(4)具有n个节点的完全二叉树的深度为

2.2、二叉树的顺序存储

   顺序存储二叉树的的思想是将树中不同的节点存入数组的不同位置,对于不满二叉树,空出来的节点对应的数组元素留空,但会造成一定的空间浪费。

   对于这种顺序存储的二叉树,不管是遍历树中节点,还是查找树中节点,都可以非常高效地完成,唯一的缺点是空间浪费很大。

2.3、二叉树的二叉链表存储

   二叉链表存储的思想是让每个节点都能“记住”它的左、右两个节点。为每个节点增加left、right两个指针,分别引用该节点的左、右两个子节点。

   二叉链表的存储方式在遍历树节点时效率不高,指定节点访问其父节点时也比较困难,程序必须采用遍历二叉树的方式来搜索其父节点。

2.4、二叉树的三叉链表存储

   三叉链表存储的思想是让每个节点不仅能“记住”它的左、右两个节点,还要“记住”它的父节点。因此,每个节点增加left、right和parent三个指针, 分别引用该节点的左、右两个子节点和父节点。

   三叉链表是对二叉链表的一种改进,既可以方便地向下访问节点,也可方便地向上访问节点。


3、遍历二叉树


   遍历二叉树指的是按某种规律依次访问二叉树的每个节点,对二叉树的遍历过程就是将非线性结构的二叉树中的节点排列成线性序列的过程。若采用顺序结构来保存二叉树节点,则直接遍历底层数组即可;若采用链表来保存二叉树的节点,则有两种遍历方式,深度优先遍历和广度优先遍历。

3.1、深度优先遍历

   先访问到树中最深层次的节点。深度优先遍历时能非常方便地利用递归来遍历每个节点。可分为三种:

DLR:先序遍历(访问根节点,递归遍历左子树,递归遍历右子树)

LDR:中序遍历(递归遍历左子树,访问根节点,递归遍历右子树

LRD:后序遍历递归遍历左子树,递归遍历右子树访问根节点

3.2、广度优先遍历

   逐层访问每层节点,先访问根(第一层)节点,然后访问第二层节点……

(1)建一个队列(先进先出),把树的根节点压入队列。

(2)从队列中弹出一个节点(第一次弹出的就是根节点),然后把该节点的左、右节点压入队列,如果没有子节点,则说明已经到达叶子节点。

(3)用循环重复执行第2步,直到队列为空。当队列为空时,说明所有的叶子节点(深度最深的层)都已经经过了队列,也就完成了遍历。


4、转换方法


   为了充分利用二叉树的简单易用性,可以将普通树转换为二叉树,以二叉树的形式来保存普通树,当程序需要树时,再将二叉树转换为普通树。

多叉树向二叉树转换方法:

(1)加虚线:同一个父节点的相邻兄弟节点之间加虚线;

(2)抹实线:每个节点只保留它与最左子节点的连线,与其他子节点的连线都被抹掉;

(3)虚改实:虚线改为实线。

二叉树向多叉树、森林转换方法:

(1)加虚线:若某节点是父节点的左子节点,则为该节点的右孩子链的所有节点分别与该节点的父节点添加连线;

(2)抹线:把有虚线的节点与原父节点的连线抹去;

(3)整理:虚改实并按层排列。

如果二叉树的根节点的右子节点链只有一个节点,那么转换出来的森林将有两棵树;如果二叉树的根节点的右子节点链有N个节点,那么转换出来的森林将有N+1棵树。


5、最优二叉树(啥夫曼树)


   带权路径最小的二叉树。对于具有n个叶子节点的哈夫曼树,一共需要2*n-1个节点。

创建哈夫曼树:

(1)根据给定的n个权值构造n棵二叉树的集合,F集合中每棵二叉树都只有一个根节点;

(2)选取F集合中两棵根节点的权值最小的树作为左、右子树以构造一棵新的二叉树,且将新的二叉树的根节点的权值设为左、右子树上的根节点的权值之和;

(3)将新的二叉树加入到F集合中,并删除第2步中被选中的两棵树;

(4)重复第2和3步,直到F集合中只剩下一棵树,最优二叉树。

规律:假设有N个叶子节点需要编码,最终得到的最优二叉树一定有N层,得到的二进制码的最大长度为N-1。


6、排序二叉树


排序二叉树要么是一棵空二叉树,要么是具有下列性质的二叉树:

(1)若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;

(2)若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;

(3)它的左、右子树也分别为排序二叉树。

采用广度优先法则来遍历排序二叉树得到的不是有序序列,采用中序遍历来遍历排序二叉树时才可以得到有序序列。


7、红黑树


   红黑树是一个更高效的检索二叉树,常常用来实现关联数组。典型的JDK提供的集合类TreeMap本身就是一棵树红黑树的实现。红黑树在原有的排序二叉树上增加了如下几个要求:

性质一:每个节点要么是红色,要么是黑色。

性质二:根节点永远是黑色的。

性质三:所有的叶子节点都空节点(即null),并且是黑色的。

性质四:每个红色节点的两个子节点都是黑色的。(从每个叶子到根的路径上不会有两个连续的红色节点。)

性质五:从任一节点到其子树中每个叶子节点的路径都包含相同数量的黑色节点。

结论:对于给定的黑色高度为N的红黑树,从根到叶子节点的最短路径长度为N-1,最长路径长度为2*(N-1)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值