数据结构与算法C语言版学习笔记(6)-树、二叉树、赫夫曼树

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、树的定义
    • 1.结点的度、树的度
    • 2.结点的逻辑关系
    • 3.树的深度
    • 4.有序树和无序树
    • 5.森林
  • 二、树的存储结构
    • (1)双亲表示法
    • (2)孩子表示法
      • ①每个结点的指针域数量等于整个树的度
      • ②每个结点的指针域数量等于自己的度
      • ③升级改进后的孩子表示法
    • (3)孩子兄弟表示法
  • 三、二叉树
    • 1.背景引出
    • 2.二叉树的特殊形态
      • (1)斜树
      • (2)满二叉树
      • (3)完全二叉树
    • 3.二叉树的性质
    • 4.二叉树的存储结构
    • 5.二叉树的遍历算法(前序、中序、后序)
      • ①前序遍历
      • ②中序遍历:
      • ③后序遍历:
    • 6.已知前序/中序/后序三者中的其二,求另外一个
    • 7.建立一颗二叉树
  • 六、线索二叉树
  • 七、赫夫曼树


前言

前面说,数据的逻辑结构包括线性结构和非线性结构,线性结构学了线性表(顺序表与链表)、栈与队列、串等,而现在要接触的树是非线性结构,它是一对多的关系,更加复杂。

一、树的定义

在这里插入图片描述
在这里插入图片描述

1.结点的度、树的度

(1)结点拥有的子树数称为结点的度(Degree)。度为0的结点称为叶结点(Leaf)或终端结点;度不为0的结点称为非终端结点或分支结点。除根结点之外,分支结点也称为内部结点。比如D有三个子树,度为3;C有两个子树,度为2。

(2)树的度是树内各结点的度的最大值。如图6-2-4所示,因为这棵树结点的度的最大值是结点D的度,为3,所以树的度也为3。
在这里插入图片描述

2.结点的逻辑关系

在这里插入图片描述
结点的子树的根称为该结点的孩子(Child),相应地,该结点称为孩子的双亲(Parent)。嗯,为什么不是父或母,叫双亲呢?对于结点来说其父母同体,唯一的一个,所以只能把它称为双亲了。同一个双亲的孩子之间互称兄弟(Sibling)。结点的祖先是从根到该结点所经分支上的所有结点。所以对于H来说,D、B、A 都是它的祖先。反之,以某结点为根的子树中的任一结点都称为该结点的子孙。

3.树的深度

结点的层次(Level)从根开始定义起,根为第一层,根的孩子为第二层。若某结点在第1层,则其子树的根就在第l+1层。其双亲在同一层的结点互为堂兄弟。显然图6-2-6中的D、E、F是堂兄弟,而G、H、1、J也是。树中结点的最大层次称为树的深度(Depth)或高度,当前树的深度为4。
在这里插入图片描述

4.有序树和无序树

如果将树中结点的各子树看成从左至右是有次序的,不能互换的,则称该树为有序树,否则称为无序树

5.森林

在这里插入图片描述在这里插入图片描述

二、树的存储结构

树的存储结构不同于线性表,由于结构的差异,很难用顺序结构来表示,这里产生了针对树的三种存储结构:
(1)双亲表示法:每个节点除了数据域外,还包含一个指向父节点的指针。根节点的指针为空。这种存储结构方便查找父节点,但是查找子节点需要遍历整个树。

(2)孩子表示法:每个节点包含一个指向第一个子节点的指针,以及一个指向兄弟节点的指针。这种存储结构方便查找子节点和兄弟节点,但是查找父节点需要遍历整个树。

(2)孩子兄弟表示法:每个节点包含一个指向第一个子节点的指针,以及一个指向下一个兄弟节点的指针。这种存储结构比较灵活,可以表示任意树形结构,但是查找父节点需要遍历整个树。

(1)双亲表示法

我们人可能因为种种原因,没有孩子,但无论是谁都不可能是从石头里出来的,所以是人一定会有父母。树这种结构也不例外,除了根结点外,其余每个结点,它不一定有孩子,但是一定有且仅有一个双亲。
我们假设以一组连续空间存储树的结点,同时在每个结点中,附设一个指示器指示其双亲结点到链表中的位置。也就是说,每个结点除了知道自己是谁以外,还知道它的双亲在哪里。它的结点结构为表6-4-1所示。
在这里插入图片描述

其中 data是数据域,存储结点的数据信息。而 parent是指针域,存储该结点的双亲在数组中的下标。所以它与链表还是有区别的,链表指针域存储的是后驱结点的地址。
在这里插入图片描述
所以我们可以通过一个结点很容易找到其双亲结点,但是很难找到其孩子节点。

如果需要解决找到孩子结点的问题,当然可以再拓展一个指针域,用来存储一个长子的位置。
在这里插入图片描述

(2)孩子表示法

顾名思义,每一个结点除了自己的数据域外,指针域存储了自己的孩子结点的位置。

①每个结点的指针域数量等于整个树的度

在这里插入图片描述
很明显,最大的缺点就是每个结点的子节点个数不一致,所以会空出许多空间没有被利用,浪费存储空间。

②每个结点的指针域数量等于自己的度

在这里插入图片描述
这也有缺点,每个结点的存储结构不同,看着很费劲。

③升级改进后的孩子表示法

为了既可以节省存储空间,又可以将存储结构看起来整齐划一,设计了升级版的孩子表示法:
在这里插入图片描述
如图,对于一棵树,变成了顺序表+链表的形式,每个结点的数据和长子指针构成了一个顺序结构的一维数组,然后每个节点的长子结点又引出链式结构,指向第二个孩子,第二个孩子结点又有一个next指针指向后驱结点即第三个孩子,如此往复。
孩子表示法结构体:
在这里插入图片描述
在这里插入图片描述

(3)孩子兄弟表示法

刚才我们分别从双亲的角度和从孩子的角度研究树的存储结构,如果我们从树结点的兄弟的角度又会如何呢?当然,对于树这样的层级结构来说,只研究结点的兄弟是不行的,我们观察后发现,任意一棵树,它的结点的第一个孩子如果存在就是唯一的,它的右兄弟如果存在也是唯一的。因此,我们设置两个指针,分别指向该结点的第一个孩子和此结点的右兄弟。
在这里插入图片描述
简而言之,一个结点的数据域是自己的数据,两个指针域,第一个指向自己的长子,第二个指向自己的右边的兄弟。
在这里插入图片描述

三、二叉树

1.背景引出

我们玩猜数字游戏, 猜0-100中的某个数,可以使用二分法。先猜50,大则猜25,小则猜75,然后再次二分。
在这里插入图片描述
这种结构就叫二叉树结构。二叉树是一种特殊的树结构,每个节点最多有两个子节点,分别称为左子节点和右子节点。

二叉树的特点有:
①每个结点最多有两棵子树,所以二叉树中不存在度大于2的结点。注意不是只有两棵子树,而是最多有。没有子树或者有一棵子树都是可以的。
②左子树和右子树是有顺序的,次序不能任意颠倒。就像人是双手、双脚,但显然左手、左脚和右手、右脚是不一样的,右手戴左手套、右脚穿左鞋都会极其别扭和难受。
③即使树中某结点只有一棵子树,也要区分它是左子树还是右子树。图6-5-3中,树1和树2是同一棵树,但它们却是不同的二叉树。就好像你一不小心,摔伤了手,伤的是左手还是右手,对你的生活影响度是完全不同的。

2.二叉树的特殊形态

(1)斜树

在这里插入图片描述
斜树是一种特殊的二叉树,所有的节点都只有左子节点或右子节点,没有同时拥有左子节点和右子节点的节点。斜树可以分为左斜树和右斜树,具体取决于所有节点只有左子节点或右子节点。

(2)满二叉树

在这里插入图片描述
满二叉树是一种特殊的二叉树,除了叶节点外,每个节点都有两个子节点。满二叉树的特点是所有的叶节点都在同一层上,并且除了叶节点外,每个节点的度数都是2。

(3)完全二叉树

在这里插入图片描述

完全二叉树是一种特殊的二叉树,除了最后一层外,其他层的节点都是满的,且最后一层的节点都靠左排列。也可以说,完全二叉树是一颗二叉树中,从上到下、从左到右依次填满节点的二叉树。

3.二叉树的性质

二叉树具有以下性质:

每个节点最多有两个子节点:每个节点最多有两个子节点,分别称为左子节点和右子节点。如果一个节点没有子节点,称为叶节点。

左子树和右子树的顺序不能颠倒:二叉树的左子树和右子树的顺序不能颠倒,即左子节点在右子节点之前。

每个节点的子树也是二叉树:二叉树的每个节点的子节点也是二叉树,即每个节点都可以看作是根节点。

二叉树的高度:二叉树的高度是指从根节点到最深叶节点的路径上的节点数。树中的节点数目为n,那么二叉树的高度最大为n-1,最小为log2(n+1)。

二叉树的遍历:二叉树的遍历有三种常用的方式,分别是前序遍历、中序遍历和后序遍历。前序遍历先访问根节点,然后递归访问左子树和右子树。中序遍历先递归访问左子树,然后访问根节点,最后递归访问右子树。后序遍历先递归访问左子树和右子树,最后访问根节点。

二叉搜索树(Binary Search Tree,简称BST):二叉搜索树是一种特殊的二叉树,其中每个节点的值都大于其左子树中的任意节点的值,且小于其右子树中的任意节点的值。这使得在二叉搜索树中进行搜索、插入和删除操作的时间复杂度为O(logn),其中n为树中节点的数量。

4.二叉树的存储结构

链式结构,一个数据域,两个指针域,分别存放指向左孩子和右孩子的指针。
在这里插入图片描述
在这里插入图片描述

5.二叉树的遍历算法(前序、中序、后序)

①前序遍历

在这里插入图片描述
关键思路就是:先根结点,再左后右。(根节点不是指A,指的是每一次遍历到的当前结点就看作根节点)
遍历每个结点的顺序是:ABDHKECFIGJ

②中序遍历:

关键思路是:先左后根节点,再右节点。
在这里插入图片描述
遍历每个结点的顺序是:HKDBEAIFCGJ

③后序遍历:

关键思路是:先左再右,根节点最后访问。
在这里插入图片描述
遍历每个结点的顺序是:KHDEBIFJGCA

6.已知前序/中序/后序三者中的其二,求另外一个

不过多解释,反正用脑子分析就行。理解原理,然后就跟推理一样,慢慢分析即可。
注意:已知前序和后序,无法求出中序。

7.建立一颗二叉树

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

// 定义二叉树节点结构体
typedef struct TreeNode {
    int val;
    struct TreeNode* left;
    struct TreeNode* right;
} TreeNode;

// 创建二叉树节点
TreeNode* createNode(int val) {
    TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
    if (newNode == NULL) {
        printf("内存分配失败\n");
        exit(1);
    }
    newNode->val = val;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}

// 构建二叉树
TreeNode* buildTree() {
    int val;
    printf("输入节点的值(输入-1表示空节点):");
    scanf("%d", &val);
    if (val == -1) {
        return NULL;
    }
    TreeNode* root = createNode(val);
    printf("构建左子树:\n");
    root->left = buildTree();
    printf("构建右子树:\n");
    root->right = buildTree();
    return root;
}

思路:buildTree 函数可以递归地创建左右子节点是因为在构建二叉树的过程中,每次调用 buildTree 函数都是在当前节点的基础上构建其左右子树。

具体来说,函数首先提示用户输入节点的值,如果输入值为 -1,则表示该节点为空,返回 NULL。否则,创建一个新的节点,并递归地调用 buildTree 函数来构建当前节点的左子树和右子树。

在递归调用中,每次调用都会创建一个新的节点,并将其赋值给当前节点的左子树或右子树指针。然后,在新的节点上,再次调用 buildTree 函数来构建其左子树和右子树。这样,通过递归的方式,就可以逐层构建整个二叉树的节点。

当用户输入 -1 表示节点为空时,会逐层返回 NULL,即构建空节点。这样,递归调用结束后,就完成了整个二叉树的构建过程。

六、线索二叉树

线索二叉树是对二叉树的一种改进,它通过添加线索(thread)来加快对二叉树的遍历操作。线索二叉树中,除了存储节点的值和左右子树指针外,还添加了线索指针,用于指向前驱节点或后继节点。

具体来说,线索二叉树中的线索指针可以分为两种类型:

前驱线索:对于每个节点,线索指针可以指向其在中序遍历中的前驱节点。
后继线索:对于每个节点,线索指针可以指向其在中序遍历中的后继节点。
线索化二叉树的过程主要包括两个步骤:

线索化左子树:在线索化当前节点的左子树时,需要将当前节点的前驱线索指针指向其在中序遍历中的前驱节点,并将前驱线索指针的后继线索指针指向当前节点。
线索化右子树:在线索化当前节点的右子树时,需要将当前节点的后继线索指针指向其在中序遍历中的后继节点,并将后继线索指针的前驱线索指针指向当前节点。
线索化完成后,可以通过线索指针直接找到任意节点的前驱节点和后继节点,从而加速对二叉树的遍历操作。
在这里插入图片描述

七、赫夫曼树

赫夫曼树(Huffman Tree),也称为最优二叉树(Optimal Binary Tree),是一种特殊的二叉树结构,常用于数据压缩算法中的赫夫曼编码

赫夫曼树的构建过程基于赫夫曼算法,其核心思想是将出现频率较高的字符或数据项放在离根节点较近的位置,而出现频率较低的字符或数据项放在离根节点较远的位置,以实现高效的压缩

具体构建赫夫曼树的步骤如下:

给定一组字符或数据项及其出现频率,根据频率从小到大排序,作为初始的叶子节点集合。

从初始的叶子节点集合中选择出现频率最小的两个节点作为左右子节点,并创建一个新的节点作为它们的父节点,父节点的频率为左右子节点频率之和。

将父节点加入到叶子节点集合中,并从集合中删除被合并的两个子节点。

重复步骤2和步骤3,直到只剩下一个节点,该节点即为赫夫曼树的根节点。

赫夫曼树的构建过程可以通过使用优先队列(Priority Queue)来实现,每次从队列中选择频率最小的两个节点进行合并。

赫夫曼树的特点是,出现频率较高的字符或数据项在树中的路径较短,而出现频率较低的字符或数据项在树中的路径较长。这样,在进行赫夫曼编码时,可以用较短的编码表示较高频率的字符或数据项,从而实现数据的压缩

赫夫曼树在数据压缩中具有重要的应用,能够有效地压缩数据并保证数据的可恢复性。

具体的赫夫曼树的图解、代码实现、性质作用等内容以后有机会再补充,这里仅了解一下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/132872.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Android 使用.9图 NinePatchDrawable实现动态聊天气泡

最近一段时间&#xff0c;在做一个需求&#xff0c;需要实现一个聊天气泡的动画效果&#xff0c;如下图所示&#xff1a; GitHub源码demo &#xff0c;建议下载demo&#xff0c;运行查看。 动态聊天气泡动画 静态聊天气泡 经过一段时间调研&#xff0c;实现方案如下: 实现方…

FM3793A-高性能PWM控制芯片 超低成本18W-20W 恒功率PD快充

产品描述&#xff1a; FM3793A是一款应用于离线反激式转换器中的高性能电流模式PWM控制器。在 FM3793A中&#xff0c;PWM开关频率最大为65KHz。在轻载和空载条件下&#xff0c;该FM3793A启动间歇模式从而降低开关频率。FM3793A具有丰富的芯片异常状况保护功能&#xff0c;如欠压…

力扣:160. 相交链表(Python3)

题目&#xff1a; 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意&#xff0c;…

基于insightface实现的人脸检测,人脸识别,insightface源码讲解。

目录 1.搭建insightface需要的环境 2.下载insightface工程 3.代码工程文件讲解 3.1 python-package 3.2 进行测试 3.3 examples 4. 人脸识别 5.代码理解&#xff1a; 1.搭建insightface需要的环境 埋个坑&#xff0c;后续再写&#xff0c;笔者在安装过程中遇到了一些问题。…

人工智能基础——Python:运行效率与时间复杂度

人工智能的学习之路非常漫长&#xff0c;不少人因为学习路线不对或者学习内容不够专业而举步难行。不过别担心&#xff0c;我为大家整理了一份600多G的学习资源&#xff0c;基本上涵盖了人工智能学习的所有内容。点击下方链接,0元进群领取学习资源,让你的学习之路更加顺畅!记得…

浅析CC中的点云配准为什么效果好于PCL?

公众号致力于分享点云处理&#xff0c;SLAM&#xff0c;三维视觉&#xff0c;高精地图相关的文章与技术&#xff0c;欢迎各位加入我们&#xff0c;一起交流一起进步,有兴趣的可联系微信&#xff1a;cloudpoint9527。本文来自点云PCL博主的分享&#xff0c;未经作者允许请勿转载…

最新大麦订单生成器 大麦订单图一键生成

1、8.6全新版 本次更新了四种订单模板生成 多模板自由切换 2、在软件中输入生成的信息&#xff0c;这里输入的是商品信息&#xff0c;选择生成的商品图片&#xff0c;最后生成即可 新版大麦订单生成 四种模板图样式展示 这个样式图就是在大麦生成完的一个订单截图&#xff…

大数据毕业设计选题推荐-生产大数据平台-Hadoop-Spark-Hive

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

内网安全-基础设施构建-cobaltstrike远控工具beacon使用

kali在CS文件目录下&#xff0c;打开终端,运行命令&#xff1a; /teamserver 192.168.77.128 123456 在windows中双击bat文件&#xff1a; 填写图下信息&#xff1a; 双击运行&#xff0c;CS上线 自查方法&#xff1a;1、kali与物理机可互通 2、物理机与windows10跳板…

[SHCTF]web方向wp

[SHCTF]web方向wp [WEEK1]babyRCE题目源码wp [WEEK1]1zzphp题目源码wp [WEEK1]ez_serialize题目源码wp [WEEK1]登录就给flag题目wp [WEEK1]生成你的邀请函吧~题目源码wp [WEEK1]飞机大战题目wp [WEEK1]ezphp题目源码wp [WEEK2]no_wake_up题目源码wp [WEEK2]MD5的事就拜托了题目…

人工智能在汽车业应用的五项挑战

在汽车行业扩展人工智能应用时需要注意的问题 随着更多企业投资于汽车人工智能 (AI) 解决方案&#xff0c;我们也愈加接近大规模部署 5 级全自动驾驶汽车。汽车行业的组织如果希望加入这场 AI 带来的颠覆性变革&#xff0c;就应该已提前考虑如何成功和大规模地将人工智能部署到…

C语言每日一题(28) 反转链表

牛客网 BM1 反转链表 题目描述 描述 给定一个单链表的头结点pHead(该头节点是有值的&#xff0c;比如在下图&#xff0c;它的val是1)&#xff0c;长度为n&#xff0c;反转该链表后&#xff0c;返回新链表的表头。 数据范围&#xff1a; 0≤n≤1000 要求&#xff1a;空间复…

LCD1602设计(1)

本文为博主 日月同辉&#xff0c;与我共生&#xff0c;csdn原创首发。希望看完后能对你有所帮助&#xff0c;不足之处请指正&#xff01;一起交流学习&#xff0c;共同进步&#xff01; > 发布人&#xff1a;日月同辉,与我共生_单片机-CSDN博客 > 欢迎你为独创博主日月同…

stm32超声波测距不准的解决方法(STM32 delay_us()产生1us)

首先要说明一下原理&#xff1a;使用stm32无法准确产生1us的时间&#xff0c;但是超声波测距一定要依赖时间&#xff0c;时间不准&#xff0c;距离一定不准&#xff0c;这是要肯定的&#xff0c;但是在不准确的情况下&#xff0c;要测量一个比较准确的时间&#xff0c;那么只能…

JavaScript从入门到精通系列第三十三篇:详解正则表达式语法(二)

文章目录 一&#xff1a;正则表达式 1&#xff1a; 检查一个字符串中是否有. 2&#xff1a;第二种关键表达 3&#xff1a;第三种关键表达 ​编辑4&#xff1a;第四种关键表达 5&#xff1a;第五种关键表达 6&#xff1a;第六种关键表达 二&#xff1a;核心表达二 1&am…

在程序中链接静态库

现在我们把上面src目录中的add.cpp、div.cpp、mult.cpp、sub.cpp编译成一个静态库文件libcalc.a。 add_library(库名称 STATIC 源文件1 [源文件2] ...) link_libraries(<static lib> [<static lib>...]) 参数1&#xff1a;指定出要链接的静态库的名字 可以是全…

Postgres的级数生成函数generate_series应用

Postgres的级数生成函数generate_series应用 引用&#xff1a;http://postgres.cn/docs/12/functions-srf.html 函数文档 函数 参数类型 返回类型 描述 generate_series(start, stop) int、bigint或者numeric setof int、setof bigint或者setof numeric&#xff08;与参数类型相…

公司注册股东选择几个人合适?

创业初期很多创业者都会选择有注册有限责任公司&#xff0c;有限责任由五十个以下的股东出资设立&#xff0c;每个股东以其所认缴的出资额为限对公司承担有限责任。那么问题来了股东人数选择几个最合适呢&#xff0c;下面上海注册公司网&#xff08;www.91kaiye.cn&#xff09;…

AMD64内存属性详解

本文参考文档为AMD64 Architecture Programmer’s Manual Volume 2: System Programming&#xff0c;版本号3.41&#xff0c;这不是对原英文文档的翻译&#xff0c;但是所有内容的排版都是根据原手册的排版来的&#xff0c;如有与官方文档冲突的内容&#xff0c;以官方文档为准…

【C++破局】C++内存管理之new与deleted剖析

​作者主页 &#x1f4da;lovewold少个r博客主页 ⚠️本文重点&#xff1a;c内存管理部分知识点梳理 &#x1f449;【C-C入门系列专栏】&#xff1a;博客文章专栏传送门 &#x1f604;每日一言&#xff1a;花有重开日&#xff0c;人无再少年&#xff01; 目录 C/C的内存分配机…