前言:
前篇学习了 数据结构的栈和队列,那么这篇继续学习树及其相关内容基础内容。
/知识点汇总/
概念:树是一种非线性结构,是由有限个节点组成的具有层次关系的集合。倒立的树模样。
有一个特殊的结点,称为根节点,根节点没有前驱。
另外的子树有且只有一个前驱,可以有0个或多个后继。
因此树是递归定义的。根在上,叶在下。
结点的度:一个结点的度就是结点含有的子树个数,称为该结点的度。
叶子节点或称为终端结点:度为0的结点就是叶子节点,也就是没有孩子的结点。
非终端结点或称为分支结点:度不为0的结点。
双亲结点或父节点:若一个结点含有子节点,则该节点称为其子节点的父节点。
孩子节点或子节点:一个结点含有的子树的根结点称为该结点的子节点。
兄弟结点:具有相同父节点的结点互称为兄弟结点。
树的度:一棵树中,最大的结点的度称为树的度。
结点的层次:从根结点开始定义:根一般为第一层,根的子结点为第二层,依次类推
树的高度或深度:树中各结点的最大层次,为该结点的深度。
堂兄弟结点:双亲位于同一层的结点为堂兄弟结点。
结点的祖先:从根结点到该结点所经分支上的所有结点都是该结点的祖先
子孙:以某结点为根的子树中任一结点都称为该结点的子孙。
森林:由若干棵互不相交的树的集合称为森林。可有树去掉根结点转化。
那么树的实现,该如何表示呢?用数组?用链表?
三种方法,假设树的度为6
方法一:
#define N 6
struct TreeNode
{
int val;
struct TreeNode* childArr[N];//指针数组
};
方法二:
struct TreeNode
{
int val;
SeqList childSL;//顺序表
//SeqList,C++的库可调用
};
方法三,最优方法:左孩子右兄弟表示法
struct TreeNode
{
int val;
struct TreeNode* leftChild;
struct TreeNode* rightBother;
};
一颗二叉树是结点的一个有限集合,该集合:
1.或者为空
2.或由一个根结点加上两棵,别称为,左子树和右子树的二叉树组成。
3.二叉树不存在度大于2的结点
4.二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树。
注意:对于任意的二叉树都是由一下几种情况复合而成的。
1.空树
2.只有根节点
3.只有左子树
4.只有右子树
5.左右子树均存在
二叉树的度不一定为2,但度为2一定是二叉树。
因为二叉树的度最大为2,即0~2
一颗二叉树,如果每一层的结点树达到最大值,那么这个二叉树就是满二叉树。
层数为:k,那么结点总数就是:2^k-1个结点
每一层都是满的,即除了叶子结点,其余所有结点的度都是2,因为只有度为0或度为2的结点。
完全二叉树是效率很高的数据结构,对于深度为k的,有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1到n的结点一一对应时,被称为完全二叉树,满二叉树是一种特殊的完全二叉树。
完全二叉树叶子节点只可能出现在最下层或次下层,并且最下层的叶子节点都位于左孩子(因为要保持连续性,不能颠倒)。
前n-1层是满的,最后一层不一定满(因为满二叉树是完全二叉树的特殊情况),但是从左到右必须是连续的。
高度为h的完全二叉树第h层的结点数:
最多就是:2^h - 1
最少为:2^(h-1)-1+1
即:[2^(h-1), 2^h-1]
1.数组 — 一层一层的存储
父子结点的关系:
左孩子 = 父结点2 +1 //奇数
右孩子 = 父结点2+2 //偶数
或者由孩子结点推父结点:
父结点 = (孩子结点-1)/2
所以非完全二叉树不适合数组结构的存储,知识和链式结构存储
一般是把数组数据看作一颗完全二叉树,并有以下要求:
小堆:任意一个父亲 <= 孩子
大堆:任意一个父亲 >= 孩子
1.堆中某个结点的值总是不大于或不小于其父结点的值
2.堆总是一颗完全二叉树
练习题1:
下列关键字序列为堆的是:
A 100 60 70 50 32 65
B 60 70 65 50 32 100
C 65 100 70 32 50 60
D 70 65 100 32 50 60
举例:
A满足:
100
60 70
50 32 65
小结:
所以有序数组是堆,但堆不一定有序;并且这里的堆和内存空间的堆不是同一个意义。
- 堆的排序 O(N*log^N) – 根结点是该数的最大值
- top k问题 – 便于求顶点问题的解决
- 搜索
一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费等问题。
并且实际应用中,也只有堆会用数组的形式存储。
即二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树。
用链表来指示元素的逻辑关系。
通常,以链表中的每一个结点,三个域组成,分别是数据域、左指针域和右指针域,左指针指向左孩子,右指针指向右孩子。
链式结构也分为二叉链和三叉链,一般是二叉链。高阶数据结构涉及三叉链。
补充知识点(备注:后面抽空单独写篇学习该部分知识点):
1.搜素二叉树:对于根节点来说,根节点的左子树都小于根结点,根节点的右子树都大于根节点。 最多查找高度次。
2.森林:是m(m≥0)棵互不相交的树的集合,其次森林是由树构成的。
3.最优二叉树(哈夫曼树):带权路径最小的二叉树称为最优二叉树,也称为哈夫曼树。
3.1.带权路径长度:设二叉树具有n个带权值的叶子结点,从根结点到各个叶子结点的路径长度与相应叶子结点权值的乘积之和,称为带权路径长度。
3.2.哈夫曼树的定义:一棵二叉树要使其带权路径长度最小,必须使权值越大的叶子节点越靠近根节点,权值越小的叶子节点越远离根节点,并且不存在度为1的结点。
4.线索二叉树:加上线索的二叉树称为线索链表,也称为线索二叉树。
4.1.线索:考虑到具有n个结点的二叉链表,在2n个指针域中只有n-1个指针域用来存储孩子节点的地址,存在n+1个空指针域,可以利用这些空指针指向该节点在某种遍历序列中的前驱或后继结点,这些指向前驱和后继结点的指针称为线索,加上线索的二叉链表就是线索链表或线索二叉树。
一般步骤:
1.加线:树中所有相邻兄弟结点之间加一条线;
2.去线:对树中的每个结点,只保留它与第一个孩子结点之间的连线,删去它与其它孩子结点之间的连线;
3.层次调整:按照二叉树结点之间的关系进行层次调整。
样例流程图,如下所示:
一般步骤:
1.将森林中的每根树转换为二叉树;
2.将每棵树的根结点视为兄弟,在所有根节点之间加上连线;
3.按照二叉树结点之间的关系进行层次调整。
样例流程图,如下所示:
一般步骤:
1.加线:若某结点x是其双亲y的左孩子,则把结点x的右孩子、右孩子的右孩子…都与结点y用线连接;
2.去线:删去原来二叉树中所有的双亲结点与右孩子结点的连线;
3.层次调整:整理1和2步骤,使之层次分明,得到树或森林。
样例流程图,如下所示:
二叉树的5个基本性质:
1.若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1)个结点。
2.若规定根节点的层数为1,则深度为h的二叉树的最大节点数为2^h - 1个(等比数列推导)
3.对任何一棵二叉树,如果度为0其叶子节点个数为n0,度为2的分支节点个数为n2,则有n0 = n2 + 1;
4.若规定根节点的层数为1,具有n个结点的满二叉树的深度,h = log2^n+1。
5.对于具有n个结点的完全二叉树,如果按照从上至下,从左至右的数组顺序对所有结点从0开始编导,则对于序号为i的节点有:
1)若i>0,i位置节点的双亲序号为:(i-1)/2 , i = 0时i为根节点编号,无双亲节点;
2)若2i+1=n,否则无左孩子;
3)若2i+2=n,否则为右孩子。
补充:
增加一个度为2的结点,一定增加一个度为0的结点。
增加一个度为1的结点,一定减少一个度为0的结点,增加一个度为0的结点.
第一题:
某二叉树共有399个节点,其中有199个度为2的节点,则该二叉树中的叶子节点数为()
A.不存在这样的二叉树 B.200 C.198 D.199
第二题:
下列数据结构中,不适合采用顺序存储结构的是()
A.非完全二叉树 B.堆 C.队列 D.栈
第三题:
在具有2n个节点的完全二叉树中,叶子节点个数为()
A.n B.n+1 C.n-1 D.n/2
第四题:
一颗完全二叉树的节点数为531个,那么这颗数的高度为()
A.11 B.10 C. 8 D.12
第五题:
一个具有767个节点的完全二叉树,其中叶子节点个数为()
A.383 B.384 C.385 D.386
参考答案:1.B 2.A 3.B 4.B 5.B