1.树的一些结论:

(1)整个树的节点个数=所有结点的度数+1

(2)一个概念的辨析:树的度(例如为n)和m叉树
树的度:表示一个树必有一个节点的度为n,且一定不为空树,节点数最少为n+1
m叉树:可以为空树,可以所有节点的度都小于m

2.二叉树的一些结论

(1)非空二叉树中:n0=n2+1

(2)完全二叉树的话:n1一定为0或1,n0与n2的和一定为奇数

3.二叉树的顺序存储

struct TreeNode{
      Elemtype value; 
      bool isEmpty;
} 

二叉树的顺序存储,是通过数组存储的。但无论是不是完全二叉树,都必须按照完全二叉树来进行存储。如果那个位置没有树,就填0,但那个位置必须有。(即最坏情况:哪怕是高度为h的,只有h个节点的树(只有右结点),也需要2的h次方减一个存储单位)

所以,一般来说,顺序存储,只适合完全二叉树。(但不是完全的也可以,但比较浪费)

4.二叉树的链式存储

typedef struct BitNode{
      Elemtype data;
      struct BitNode *lchild,*rchild;
}BitNode,*BitTree;

n个节点,应该有2n个指向域,但只会有n-1个指针,所以一定有n+1个空链域。

因为二叉树方便找左右孩子节点,但不方便找父亲节点,所以可以引入一个父亲节点。

typedef struct BitNode{
      Elemtype data;
      struct BitNode *lchild,*rchild;
      struct BitNode *parent;
}BitNode,*BitTree;

5.二叉树的遍历(全部需要栈,无论是不是递归算法,但是线索的前中不需要,线索后需要)
先序——前缀表达(给定先序序列,二叉树数量为2n!/n!/n!/(n+1))
中序——中缀表达
后序——后缀表达
层序遍历:从上到下,从左至右

6.由遍历推二叉树
前/后/层次+中可以推(都是先找根节点在哪,然后在分左右子树,再推)

7.线索二叉树(一种逻辑与存储(物理)结构)(空链域是指没有孩子指针也没有线索指针)

typedef struct ThreadNode{
      Elemtype data;
      struct ThreadNode *lchild,*rchild;
      int ltag,rtag;------左右线索标志
}ThreadNode,*ThreadTree;

中序线索化(只要没有左右孩子,ltag和rtag就为1)

先序线索化(只有先序线索化会有转圈的问题(第一张图,在D这个点时,会发送转圈的情况),只有ltag=0 才能先序线索化)

后序同中序(基本代码相同)

线索二叉树找前序和后继(先序二叉树找前驱和后序二叉树找后继都需要使用三叉链表,找父节点,然后再找)

8.树

(1)双亲表示法

增:新增元素,直接在表中添加即可,无需按顺序

删:(1)将后面的数字改为-1(会增加空数据,降低效率) (2)删除该元素以及其子元素(如果有)

优点:查找双亲方便
缺点:查找孩子节点需要从头遍历

(2)孩子表示法

(3)孩子兄弟表示法(即树与二叉树的转换)

(4)森林和树的转换

(5)树的遍历
树的先根遍历——对应二叉树的先序遍历(深度优先遍历)

树的后根遍历——对应二叉树的中序遍历(深度优先遍历)

树的层序遍历——从上至下,从左至右(广度优先遍历)

(6)森林的遍历
森林的先序遍历——所有树的先序遍历

森林的中序遍历——所有树的后序遍历

遍历总结:

(7)哈夫曼树的构造

(8)如何对数据编码(无前缀编码:即所有的字母或数据皆为叶子节点)

9.并查集

(1)概念和基本操作

并查集为一个个树的集合,ACD为根结点,数列中的数字表示父节点的数组下标,而根节点的为-1.

最简单的查找和合并代码如右边所示。

(2)

合并操作的优化:将两个树合并为一个时,查找某个数据,最差的时间复杂度相当于O(n),所以我们在合并时需要将树的高度弄得尽量小,即将小树合并到大树里面。

所以我们在数组中用树的结点的相反数做对应数组的值

(3)

查找操作的优化:

从L一直向上查询到根节点A的路径叫查找路径,优化方式为压缩路径,先通过查找路径找到根节点,再把路径上的所有结点的父节点变为根节点。

优化的本质是把树变矮,时间复杂度减小


悠悠我心
7 声望1 粉丝

« 上一篇
栈与队列
下一篇 »
图及其应用