数的介绍

树型结构:
元素之间存在一对多关系的数据结构,适合存储具有层次关系的数据模型,如:文件树、组织关系、族谱。

树的相关术语:
根结点:树的最顶层结点,一棵树最多只有一个根结点。
双亲结点、父结点:结点的上一层结点,一个结点只有唯一一个双亲结点。
子结点:结点的下层结点,可以有若干个。
叶子节点:没有子结点的结点。
树的高度:树的层数
树的密度:树的结点数量

树的种类:
普通树:只有一个双亲结点,子结点的数量任意。
二叉树:一个结点最多有两个孩子。

B树:多路平衡查找树,
    多路:最多有M个子结点
    平衡:所有子树的高度相差不超过1
    查找:所有结点是有序的
B树和B+树了解即可,普通树一般成二叉树研究。

二叉树的种类:
性质1:在二叉树的第 i 层上至多有2^(i-1)个结点
性质2:深度为k的二叉树至多有2^k-1个结点
性质3:对任何一颗二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1。
n0+n1+n2 = n
n1+n2*2 = n-1
性质4:具有n个结点的完全二叉树的深度为[log(n)]+1([x]表示不大于x的最大整数)
性质5:如果对一棵有n个结点的完全二叉树(其深度为[log(n)]+1)的结点按层序编号(从第1层到第[log(n)]+1层,每层从左到右),对任一结点i(1<=i<=n)有:
(1).如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲是结点[i/2]
(2).如果2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩子是结点2i
(3).如果2i+1>n,则结点i无右孩子;否则其右孩子是结点2i+1
满二叉树:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树,每层的结点数量是:2(n-1),总结点数是:2n-1。
完全二叉树:
除了最后一层外的所有层的结点数是:2^(n-1)。
最后一层的结点按照从左到右的顺序排列。
有序二叉树:
左子结点比双亲结点小,右子结点比双亲结点大,所有结点都遵循该规则。
线索二叉树:
给普通二叉树结点,增加上线索,使用它能够以循环的方式遍历,提高遍历速度。
哈夫曼树:带权重的二叉树。
平衡二叉树:左右子树高度相差不超过1。
红黑树:接近平衡的二叉树,伪平衡二叉树。
堆:
大根堆:双亲结点比左右子结点都大。
小根堆:双亲结点比左右子结点都小。

二叉树的链式存储:
每个结点(元素)由三部分组成:

左子树指针
右子树指针

优点:能很清晰的表示树的结构,对内存的要求低,节约内存。
缺点:只能逐级访问,递归遍历,可能产生内存碎片。

二叉树的顺序存储:
注意:需要把普通二叉树补全为完全二叉树。
[] [#][] [#][#][][] [][][][][][][]

前提:节点的下标从1开始排列
i/2 = 父节点下标        
i*2 = 左子节点下标
i*2+1 = 右子节点下标

优点:创建树方便,计算高度、密度速度快,使用的整块内存不易产生内存碎片。

缺点:对内存的要求高,当树比较稀疏时,对内存浪费极高,转换成完全二叉树时麻烦。

有序二叉树:
左右子树与根结点的关系必须满足:左 < 根 <= 右
当采用中序遍历时有序二叉树的遍历结果是从小到大的。
当它结点均匀、平衡,查找效率接近二分查找,
如果不均匀且呈单支状分布它查找的效率接近链表。
注意:创建有序二叉树的目的是为了能够借助它的二分查找特性,快速查找数据。

线索二叉树:
当结点的右子树为空时,让它指向即将要访问的下一个结点,然后就可以使用循环来遍历这棵树,提高遍历的效率。

堆:
堆是一种特殊的二叉树,它对结点的位置不做要求,所以一般以完全二树或满二叉来存储它。

哈夫曼树:
结点由数据+权重(数据出现的概率)组成,权重越高结点的层数越小。
创建过程:
1、把所有的数据和权重创建成结点(子树),也被称为创建森林。
2、然后根据权重排序,把权重最小的两棵子树合并形成新的子树,并成为它的左右子树。
3、再把新合并的子树与现在的森林进行排序,重复2上步骤,直到没有子树。
4、记录每个带数据的结点,从根据结点访问的路径,生成哈夫曼编码,由0和1组成,0表示走了左子树,1表示走了右子树。
5、在之后存储数据时,用它的哈夫曼编码共代替数据,达到压缩数据的目的。
6、根据哈夫曼编码,从哈夫曼树中找到对应数据的过程叫解压数据。

平衡二叉树:
平衡二叉树(AVL)首先是一棵有序二叉树,为了解决有序二叉树不均匀导致查询速度过低,而调整它左右平衡,使有序二叉树以最快的速度查询数据。

二叉树的遍历:
A
/
B C
/ /
D E F
/ \
G H J
/
I

ABCD#EFGH###J####I
前序:根 左 右
    第一个元素为根结点
    A B D G H I C E J F
    A B D G # # H I # # # # C E # J # # F # #
中序:左 根 右
    最后一元素为根结点
    G D I H B A E J C F
    GDIHBAEJCF
后序:左 右 根
    根结点左边的都是左子树,根结点右边的都是右子树。
    G I H D B J E F C A
注意:所有子树都要遵循规则,要把每个结点当作一棵子树看待。
1、根据二叉树写出前、中、后遍历顺序。
2、根据 前序+中序 中序+后序 还原二叉树
    G D I H B A E J C F 中
    G I H D B J E F C A 后  
    1、根据后序确定根结点
    2、根中序和根确定左右子树的数量
    3、然后根据左右子树的数量确定,左右子树的后序
    4、再使用同样的方法构建左右子树
    G D I H B          E J C F
    G I H D B          J E F C

作业:
根据前序和中序创建二叉树:
TreeNode* create_tree(char* dlr,char* ldr,size_t len)
{

}

层序遍历二叉树:
void level_show(TreeNode* tree);

判断树B是否是树A的子结构
bool is_child_struct(TreeNode* A,TreeNode* B);

把一棵二叉树,调整成它的镜像树
void mirror_tree(TreeNode* tree);

找到中序遍历的第一个结点:
TreeNode* first_ldr_tree(TreeNode* tree);

1、判断二叉树是否对称。
2、按之字型遍历二叉树。
3、有序二叉树的倒数第K个结点。
    右 根 左

完全二叉树除最后一层,其他层都是满结点的。
所以这里总结点200个,这里是偶数,可以判断度为1的结点是1个。
根据二叉树性质n0 = n2 + 1;叶子结点数量等于度为2的结点数+1
n0 + n1 + n2 = 200
n0 + n1 + n0 -1 =200;
2n0 = 201-n1 = 200 (完全二叉树度为1的结点个数要么1,要么0. 叶子结点数为整数,这里也可以推断出度为1的结点个数是1)
n0 = 100
叶子结点数是100

posted @ 2021-08-10 13:39  de06  阅读(166)  评论(0编辑  收藏  举报