【数据结构 - 树和二叉树】自学笔记记录(完结)_一颗完全二叉树有5000个结点,其叶结点的个数-程序员宅基地

技术标签:   二叉排序树  二叉树  哈夫曼树  数据结构笔记  数据结构  

目录

一、树和二叉树的定义

1、树的基本术语

2、二叉树的定义

4、二叉树的性质 

满二叉树

完全二叉树   

5、树和二叉树的区别

二、遍历二叉树和线索二叉树

1、创建二叉树

2、遍历二叉树

 1、前序遍历 DLR

2、中序遍历 LDR

3、后序遍历 LRD

4、层次遍历

3、二叉树的重构 

4、线索化二叉树

1、概念

 2、代码实例

五、二叉树的基本操作

1、查找元素e的节点的位置

2、计算二叉树的深度

3、计算叶子结点个数

 4、计算节点个数

六、二叉树的转换

1、树与二叉树转换

 2、森林与二叉树转换

 3、二叉树到树到森林的转换

七、哈夫曼树及其应用

1、哈夫曼树基本概念

2、哈夫曼树的构造算法

 3、哈夫曼编码

八、二叉排序树

1、二叉排序树概念

2、二叉排序树——存储结构

3、二叉排序树——查找

4、二叉排序树——插入

九、平衡二叉排序树(AVL)

1、概念

2、平衡二叉树的平衡旋转

1、LL平衡旋转 

 2、RR平衡旋转

3、LR平衡旋转

4、RL平衡旋转


一、树和二叉树的定义

1、树的基本术语

① 结点的度:结点拥有的子树数量

② 树的度:树内结点度的最大值

③ 叶子:度为0的结点

④ 结点的层次和树的深度

 ⑤ 森林:m棵互不相交的树的集合

 ⑥ 边数+1 = 结点数

2、二叉树的定义

① 每个结点至多有2个棵子树,即二叉树中不存在度大于2的结点

     没有子树或有一颗子树都是可以的。

② 二叉树的子树有左右之分,且其次序不能颠倒

③ 即使树的某结点只有一颗子树,也要区分它是左子树和右子树

二叉树不是树的特殊情况,它们是两个概念

二叉树的结点个数可以为0

4、二叉树的性质 

① 二叉树的第 i 层最多有  2{_{}}^{i-1} 个结点,至少有1个结点;

② 深度为 k 的二叉树至多有  2^{​{_{}}^{k}}-1 个结点,至少有k个结点;

③ 叶子数为n_{0},度为2的结点数为n_{2},则 n_{0}=n_{2}+1

满二叉树

 一棵深度为 k^{} 且有 2{_{}}^{k}-1 个结点的二叉树

 

所有分支结点都有左子树和右子树,叶子结点都在最下一层
② 只有度为0和度为2的结点
含n个结点的满二叉树的深度为 log_2{(n+1)}

     叶子结点个数为 \frac{n}{2}+1(向下取整)

    度为2的结点为 \frac{n}{2}  (向下取整)

完全二叉树   

叶子结点只可能出现在层次最大的两层出现
最下一层中的叶子结点都依次排列在该层最左边的位置上
如果有度为1的结点,只可能有一个,且该结点最多只有左孩子而无右孩子 

④ 满二叉树是特殊的完全二叉树

 度为1的结点最多有1个

 含n个结点的完全二叉树的深度为  log_2{n}  +1  (向下取整)

 含n个结点的完全二叉树,对任意结点 i:

        (1)如果i>1,则其双亲是  i / 2 ⌋  (向下取整)

        (2)如果2i>n,则结点 i 无孩子(结点i为叶子结点);否则其左孩子是结点 2i

        (3)如果2i+1>n,则结点 i 无右孩子;否则其右孩子是结点 2i+1

例1、一棵完全二叉树有5000个结点,则其叶结点个数是(2500) 

      n0+n1+n2=5000,因为n0=n2+1,则2*n2+1+n1=5000,因此n1一定是奇数

     因为完全二叉树,其中度为1的结点个数最多为1个,则n1=1,则n2=2499,则n0=2500

例2、二叉链表:n个结点共2n个指针,其中有效指针为n-1,则空指针数为2n-(n-1)=n+1

                结点-1 = 有效指针数

         三叉链表:n个结点共3n个指针,其中有效指针为n-1,则空指针数为3n-2(n-1)=n+2

5、树和二叉树的区别

① 树的结点个数至少为1,二叉树的结点个数可以为0

② 树的最大度数没有限制,二叉树最大度数不能超过2

③ 树的结点无左右之分,二叉树的结点有左右之分

将树转化为二叉树的目的:

树可采用二叉树的存储结构并利用二叉树的已有算法解决树的有关问题

二、遍历二叉树和线索二叉树

1、创建二叉树

//按先序遍历创建二叉树
Status CreateBiTree( BiTree &T )
{
    char c;
    scanf("%c",&c);

    if(c == ' ') T = NULL;
    else{
        
        if(!(T = (BiTNode*)malloc(sizeof(BiTNode)))) return;
        T->data = c;
        CreateBiTree(T->lchild);
        CreateBiTree(T->rchild);

    }
}

2、遍历二叉树

1、遍历顺序          (D为根   L为左子树  R为右子树)

① DLR   先序遍历

② LDR   中序遍历

③ LRD   后序遍历

1、先序遍历:根节点 → 左节点 → 右节点;
2、中序遍历:左节点 → 根节点 → 右节点;
3、后序遍历:左节点 → 右节点 → 根节点; 

 1、前序遍历 DLR

//递归算法
void PreOrderTraverse(BiTree T, int level)
 {
     if (T) 
     {
          printf("data = %c level = %d\n ", T->data, level);
          PreOrderTraverse(T->lchild, level + 1);
          PreOrderTraverse(T->rchild, level + 1);
     }  
     
 }

2、中序遍历 LDR

//递归算法
void InOrderTraverse(BiTree T, int level)
 {
     if (T) 
     {
          PreOrderTraverse(T->lchild, level + 1);
          printf("data = %c level = %d\n ", T->data, level);
          PreOrderTraverse(T->rchild, level + 1);
     }  
     
 }

//非递归算法
void InOrderTraverse(BiTree T)
{
    InitStack(S);
    p = T;
    while(p||!StackEmpty(S))
    {
        if(p) 
        {
            Push(S,p);
            p = p->lchild;
        }else{
                Pop(S,p);
                printf("%c ",p->data);
                p = p->rchild;
        }
    }
}

3、后序遍历 LRD

//递归算法
void PostOrderTraverse(BiTree T, int level)
 {
     if (T) 
     {
          PreOrderTraverse(T->lchild, level + 1);
          PreOrderTraverse(T->rchild, level + 1);
          printf("data = %c level = %d\n ", T->data, level);
     }  
     
 }

4、层次遍历

c++ queue 队列

queue <元素类型> q1;

q.push() //在队尾插入一个元素
q.pop()  //删除队列第一个元素
q.size() //返回队列中元素个数
q.empty() //如果队列空则返回true
q.front() //返回队列中的第一个元素
q.back() //返回队列中最后一个元素
void levelOrderTraverse (Bitree T)
{
    if(T == NULL) return;  //空树
    
    queue <BiTNode*> q; //创建队列
    q.push(T);  //将根节点入队

    while(!q.empty())
    {
        BiTNode *node = q.front();  //取头结点
        printf("%d ",node->data);
        if(node->left) q.push(node->left);
        if(node->right) q.push(node->right);
        p.pop();  //头结点出队
    }
}

3、二叉树的重构 

4、线索化二叉树

1、概念

 2、代码实例

#include <stdio.h>
#include <stdlib.h>

typedef char ElemType;

typedef enum PointerTag{Link,Thread}; //枚举类型 Link=0 Thread=1

typedef struct BiThrNode
{
    ElemType data;
    struct BiThrNode *lchild,*rchild;
    PointerTag ltag,rtag;
}BiThrNode, *BiThrTree;

BiThrTree pre; //全局变量

//前序遍历 创建二叉树
void CreateBiThrTree( BiThrTree *T )
{
    char c;
    scanf("%c",&c);

    if(c == ' ') *T = NULL;
    else 
    {
        *T = (BiThrNode*)malloc(sizeof(BiThrNode));
        (*T)->data = c;
        (*T)->ltag = Link; //初始化左右标识
        (*T)->rtag = Link;

        CreateBiThrTree(&(*T)->lchild);
        CreateBiThrTree(&(*T)->rchild);
    }
}

//
void InOrderThreading(BiThrTree *p,BiThrTree T)
{
    *p = (BiThrTree)malloc(sizeof(BiThrNode));
    (*p)->ltag = Link;
    (*p)->rtag = Thread;
    (*p)->rchild = *p;
    if(!T)
    {
        (*p)->lchild = *p;
    }
    else {
        
        (*p)->lchild = T;
        pre = *p;
        InThreading(T);
        pre->rchild = *p;
        pre->rtag = Thread;
        (*p)->rchild = pre;
    }
}

//中序遍历线索化
void InThreading( BiThrTree T )
{
    if( T )
    {
        InThreading( T->lchild ); //递归左孩子线索化
        
        if(!T->lchild)
        {
            T->ltag = Thread; //没有左孩子 ltag改为1
            T->lchild = pre;
        }

        if(!pre->rchild)
        {
            pre->rtag = Thread;
            pre->rchild = T;
        }

        pre = T;

        InThreading( T->rchild ); //递归右孩子线索化
    }
}

int main()
{
    BiThrTree P,T = NULL;
    CreateBiThrTree(&T);
    InOrderThreading( &P, T );
    return 0;
}

五、二叉树的基本操作

1、查找元素e的节点的位置

BiTNode *SearchNode(BiTree &T,ElemType e)
{
    if(!T) return;

    if(T->data == e) return T;
    else
    {
        BiTNode *p = SearchNode(T->lchild,e);
        if(!p) return SearchNode(T->rchild,e);
        return p;
    }
}

2、计算二叉树的深度

int BiTreeHigh(BiTree &T)
{
    int h1,h2;
    if(T)
    {
        h1 = BiTreeHigh(T->lchild);
        h2 = BiTreeHigh(T->rchild);
        return h1>h2? ++h1:++h2;
    }
    return 0;
}

3、计算叶子结点个数

int CountLeaf(BiTree &T)
{
    if(T)
    {
        if(!T->lchild && !T->rchild)
            return 1;
        else
            return CountLeaf(T->lchild) + CountLeaf(T->rchild);
    }
    return 0;
}

 4、计算结点个数

int CountNodes(BiTree &T)
{
    if(T)
    {
        if(!T->lchild && !T->rchild)
            return 1;
        else 
            return 1 + CountNodes(T->lchild) + CountNodes(T->rchild);
    }
    return 0;
}

六、二叉树的转换

1、树与二叉树转换

第一步:把树中所有兄弟结点之间加一条连线

第二步:对于每个结点,除保留其长子的连线外,去掉该结点与其他孩子的连线

第三步:调整位置

 

 2、森林与二叉树转换

第一步:将每棵树转换为二叉树

第二步:将每棵二叉树的根节点视为兄弟,从左至右依次相连

第三步:调整位置

 

 

 3、二叉树到树到森林的转换

第一步:若结点x是其双亲y的左孩子,则把结点x的右孩子、右孩子的右孩子、……都与双亲y连接起来

第二步:去除所有双亲到右孩子之间的连线

第三步:调整位置

 

               

七、哈夫曼树及其应用

1、哈夫曼树基本概念

1、结点的路径长度:从根结点到该结点路径上的连接数

 2、树的路径长度:树中每个叶子结点的路径长度之和

 3、结点的带权路径长度:结点路径长度 × 结点权值

 4、树的带权路径长度(WPL):树中所有叶子结点带权路径长度之和

5、哈夫曼树:由n个带权叶子结点构成的所有二叉树中带权路径长度最短的二叉树

        ① 哈夫曼树不存在度为1的结点 只有度为0和2大结点

        ② n个叶子结点的哈夫曼树有2n-1个结点 (结点数是奇数)

                证:哈夫曼树中只有度为0和2的结点,那么度为0的叶子结点为n个,设度为2的

                       结点个数为y个,根据二叉树的性质,n0 = n2 + 1 ,即n = y+1,y = n-1,                                总结点数为2n-1。

2、哈夫曼树的构造算法

eg:w = {5,29,7,8,14,23,3,11}

 

 3、哈夫曼编码

1、前缀码:如果在一个编码系统中,任一个编码都不是其他任何编码的前缀,则称该编码系统中的编码是前缀码。例如,一组编码01,001,010,100,110就不是前缀码,因为01是010的前缀,若去掉01或010就是前缀码。

2、哈夫曼编码:对一棵具有n个叶子的哈夫曼树,若对树中的每个左分支赋予0右分支赋予1,则从根到每个叶子的通路上,各分支的赋值分别构成一个二进制串,该二进制串就称为哈夫曼编码。

八、二叉排序树

1、二叉排序树概念

① 若它左子树不为空,则左子树上所有结点均小于它的根节点的值 

② 若它右子树不为空,则右子树上所有结点均大于它的根节点的值 

2、二叉排序树——存储结构

typedef struct BiTNode
{
    int data;
    struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;

3、二叉排序树——查找

(1)若二叉排序树为空,则查找失败,返回空指针。

(2)若二叉排序树非空,将给定值key与根结点的关键字T->data.key进行比较:

        ① 若key等于T->data.key,则查找成功,返回根结点地址;

        ② 若key小于T->data.key,则进一步查找左子树;

        ③ 若key大于T->data.key,则进一步查找右子树。

//指针f指向T的双亲,初始值为NULL
//若查找成功,p指向该节点
//若查找不成功,p指向查找路径上访问的最后一个结点

Status SearchBST( BiTree T, int key, BiTree f, BiTree *p) 
{
   		if(!T) //查找不成功
        {
            *p = f;
            return 0;
        }      	 
   	    else if (key == T->data) //查找成功
        {
            *p = T;
            return 1;
        }  
	    else if (key < T->data)
            return SearchBST(T->lchild,key,T,p);	 //在左子树中继续查找
        else 
            return SearchBST(T->rchild,key,T,p);     //在右子树中继续查找
}

4、二叉排序树——插入

若二叉排序树为空,则插入结点为根节点
当待插入的值大于根结点的值,且根节点的右子树为空时,则将待插入的结点当作右子树插入
当待插入的值小于根节点的值,且根节点的左子树为空时,则将待插入的结点当作左子树插入
Status InsertBST( BiTree *T, int key )
{
    BiTree p,s;
    if(!SearchBST(*T,key,NULL,&p)) //查找不到才插入
    {
        s = (BiTree)malloc(sizeof(BiTNode));
        s->data = key;
        s->lchild = s->rchild = NULL;
        
        //p指向查找路径上访问的最后一个结点

        if(!p)  *T = s;  //如果为空树 插入s为新根节点
        else if(key < p->data)
                p->lchild = s;
        else
                p->rchild = s;
        return 1;
    }
    else return 0;
}

九、平衡二叉排序树(AVL)

1、概念

平衡因子任一结点的左右子树高度差

任一结点的平衡因子只能取:-1、0 、1
如果树中任意一个结点的平衡因子的绝对值大于1,则这棵二叉树就失去平衡,不再是 AVL树 

                      非平衡二叉排序树                                                                                                                               平衡二叉排序树   

上图9这个结点的左子树高度为2,右子树高度为0,高度差为2 

2、平衡二叉树的平衡旋转

如果在一棵AVL树中插入一个新结点,就有可能造成失衡,此时必须重新调整树的结构,使之恢复平衡。我们称调整平衡过程为平衡旋转。 

1、LL平衡旋转 

 2、RR平衡旋转

3、LR平衡旋转

4、RL平衡旋转

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_61639349/article/details/124090354

智能推荐

leetcode 172. 阶乘后的零-程序员宅基地

文章浏览阅读63次。题目给定一个整数 n,返回 n! 结果尾数中零的数量。解题思路每个0都是由2 * 5得来的,相当于要求n!分解成质因子后2 * 5的数目,由于n中2的数目肯定是要大于5的数目,所以我们只需要求出n!中5的数目。C++代码class Solution {public: int trailingZeroes(int n) { ...

Day15-【Java SE进阶】IO流(一):File、IO流概述、File文件对象的创建、字节输入输出流FileInputStream FileoutputStream、释放资源。_outputstream释放-程序员宅基地

文章浏览阅读992次,点赞27次,收藏15次。UTF-8是Unicode字符集的一种编码方案,采取可变长编码方案,共分四个长度区:1个字节,2个字节,3个字节,4个字节。文件字节输入流:每次读取多个字节到字节数组中去,返回读取的字节数量,读取完毕会返回-1。注意1:字符编码时使用的字符集,和解码时使用的字符集必须一致,否则会出现乱码。定义一个与文件一样大的字节数组,一次性读取完文件的全部字节。UTF-8字符集:汉字占3个字节,英文、数字占1个字节。GBK字符集:汉字占2个字节,英文、数字占1个字节。GBK规定:汉字的第一个字节的第一位必须是1。_outputstream释放

jeecgboot重新登录_jeecg 登录自动退出-程序员宅基地

文章浏览阅读1.8k次,点赞3次,收藏3次。解决jeecgboot每次登录进去都会弹出请重新登录问题,在utils文件下找到request.js文件注释这段代码即可_jeecg 登录自动退出

数据中心供配电系统负荷计算实例分析-程序员宅基地

文章浏览阅读3.4k次。我国目前普遍采用需要系数法和二项式系数法确定用电设备的负荷,其中需要系数法是国际上普遍采用的确定计算负荷的方法,最为简便;而二项式系数法在确定设备台数较少且各台设备容量差..._数据中心用电负荷统计变压器

HTML5期末大作业:网页制作代码 网站设计——人电影网站(5页) HTML+CSS+JavaScript 学生DW网页设计作业成品 dreamweaver作业静态HTML网页设计模板_网页设计成品百度网盘-程序员宅基地

文章浏览阅读7k次,点赞4次,收藏46次。HTML5期末大作业:网页制作代码 网站设计——人电影网站(5页) HTML+CSS+JavaScript 学生DW网页设计作业成品 dreamweaver作业静态HTML网页设计模板常见网页设计作业题材有 个人、 美食、 公司、 学校、 旅游、 电商、 宠物、 电器、 茶叶、 家居、 酒店、 舞蹈、 动漫、 明星、 服装、 体育、 化妆品、 物流、 环保、 书籍、 婚纱、 军事、 游戏、 节日、 戒烟、 电影、 摄影、 文化、 家乡、 鲜花、 礼品、 汽车、 其他 等网页设计题目, A+水平作业_网页设计成品百度网盘

【Jailhouse 文章】Look Mum, no VM Exits_jailhouse sr-iov-程序员宅基地

文章浏览阅读392次。jailhouse 文章翻译,Look Mum, no VM Exits!_jailhouse sr-iov

随便推点

chatgpt赋能python:Python怎么删除文件中的某一行_python 删除文件特定几行-程序员宅基地

文章浏览阅读751次。本文由chatgpt生成,文章没有在chatgpt生成的基础上进行任何的修改。以上只是chatgpt能力的冰山一角。作为通用的Aigc大模型,只是展现它原本的实力。对于颠覆工作方式的ChatGPT,应该选择拥抱而不是抗拒,未来属于“会用”AI的人。AI职场汇报智能办公文案写作效率提升教程 专注于AI+职场+办公方向。下图是课程的整体大纲下图是AI职场汇报智能办公文案写作效率提升教程中用到的ai工具。_python 删除文件特定几行

Java过滤特殊字符的正则表达式_java正则表达式过滤特殊字符-程序员宅基地

文章浏览阅读2.1k次。【代码】Java过滤特殊字符的正则表达式。_java正则表达式过滤特殊字符

CSS中设置背景的7个属性及简写background注意点_background设置背景图片-程序员宅基地

文章浏览阅读5.7k次,点赞4次,收藏17次。css中背景的设置至关重要,也是一个难点,因为属性众多,对应的属性值也比较多,这里详细的列举了背景相关的7个属性及对应的属性值,并附上演示代码,后期要用的话,可以随时查看,那我们坐稳开车了······1: background-color 设置背景颜色2:background-image来设置背景图片- 语法:background-image:url(相对路径);-可以同时为一个元素指定背景颜色和背景图片,这样背景颜色将会作为背景图片的底色,一般情况下设置背景..._background设置背景图片

Win10 安装系统跳过创建用户,直接启用 Administrator_windows10msoobe进程-程序员宅基地

文章浏览阅读2.6k次,点赞2次,收藏8次。Win10 安装系统跳过创建用户,直接启用 Administrator_windows10msoobe进程

PyCharm2021安装教程-程序员宅基地

文章浏览阅读10w+次,点赞653次,收藏3k次。Windows安装pycharm教程新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入下载安装PyCharm1、进入官网PyCharm的下载地址:http://www.jetbrains.com/pycharm/downl_pycharm2021

《跨境电商——速卖通搜索排名规则解析与SEO技术》一一1.1 初识速卖通的搜索引擎...-程序员宅基地

文章浏览阅读835次。本节书摘来自异步社区出版社《跨境电商——速卖通搜索排名规则解析与SEO技术》一书中的第1章,第1.1节,作者: 冯晓宁,更多章节内容可以访问云栖社区“异步社区”公众号查看。1.1 初识速卖通的搜索引擎1.1.1 初识速卖通搜索作为速卖通卖家都应该知道,速卖通经常被视为“国际版的淘宝”。那么请想一下,普通消费者在淘宝网上购买商品的时候,他的行为应该..._跨境电商 速卖通搜索排名规则解析与seo技术 pdf

推荐文章

热门文章

相关标签