数据结构--》解锁数据结构中树与二叉树的奥秘(二)

news2024/10/5 14:15:25

        数据结构中的树与二叉树,是在建立非线性数据结构方面极为重要的两个概念。它们不仅能够模拟出生活中各种实际问题的复杂关系,还常被用于实现搜索、排序、查找等算法,甚至成为一些大型软件和系统中的基础设施。

        无论你是初学者还是进阶者,本文将为你提供简单易懂、实用可行的知识点,帮助你更好地掌握树和二叉树在数据结构和算法中的重要性,进而提升算法解题的能力。接下来让我们开启数据结构与算法的奇妙之旅吧。

目录

二叉树的线索化

堆的定义及其建立

树与森林

霍(哈)夫曼树


二叉树的线索化

线索化二叉树(Threaded Binary Tree)是一种对二叉树进行改造的方法,使得二叉树的遍历更加高效。在线索化二叉树中,除了存储左右子节点的指针外,还存储了一些额外的线索信息,用于快速定位前驱和后继节点。

中序线索化二叉树:将二叉树的空指针域利用起来,指向该节点的中序遍历的前驱节点和后继节点。

中序线索二叉树的存储:

先序线索化二叉树:将二叉树的空指针域利用起来,指向该节点的中序遍历的前驱节点和后继节点。 

先序线索二叉树的存储: 

后序线索化二叉树:将二叉树的空指针域利用起来,指向该节点的中序遍历的前驱节点和后继节点。  

先序线索二叉树的存储: 

下面是使用C语言实现先序、中序、后续线索化的代码示例:

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

// 定义二叉树节点结构
typedef struct Node {
    int data;
    struct Node* left;
    struct Node* right;
    int isThreaded; // 标志位,用于线索化
} Node;

// 创建新节点
Node* createNode(int data) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = data;
    newNode->left = NULL;
    newNode->right = NULL;
    newNode->isThreaded = 0;
    return newNode;
}

// 先序线索化
void preorderThreading(Node* root, Node** prev) {
    if (root == NULL) {
        return;
    }
    
    if (*prev != NULL && (*prev)->right == NULL) {
        (*prev)->right = root;  // 将前驱节点的右指针指向当前节点
        (*prev)->isThreaded = 1; // 将前驱节点的线索标志位置为1
    }
    
    if (root->left == NULL) {
        root->left = *prev;  // 将当前节点的左指针指向前驱节点
        root->isThreaded = 1; // 将当前节点的线索标志位置为1
    }
    
    *prev = root;
    
    if (!root->isThreaded) {
        preorderThreading(root->left, prev);
    }
    preorderThreading(root->right, prev);
}

// 中序线索化
void inorderThreading(Node* root, Node** prev) {
    if (root == NULL) {
        return;
    }
    
    inorderThreading(root->left, prev);
    
    if (*prev != NULL && (*prev)->right == NULL) {
        (*prev)->right = root;  // 将前驱节点的右指针指向当前节点
        (*prev)->isThreaded = 1; // 将前驱节点的线索标志位置为1
    }
    
    if (root->left == NULL) {
        root->left = *prev;  // 将当前节点的左指针指向前驱节点
        root->isThreaded = 1; // 将当前节点的线索标志位置为1
    }
    
    *prev = root;
    
    inorderThreading(root->right, prev);
}

// 后续线索化
void postorderThreading(Node* root, Node** prev) {
    if (root == NULL) {
        return;
    }
    
    postorderThreading(root->left, prev);
    postorderThreading(root->right, prev);
    
    if (*prev != NULL && (*prev)->right == NULL) {
        (*prev)->right = root;  // 将前驱节点的右指针指向当前节点
        (*prev)->isThreaded = 1; // 将前驱节点的线索标志位置为1
    }
    
    if (root->left == NULL) {
        root->left = *prev;  // 将当前节点的左指针指向前驱节点
        root->isThreaded = 1; // 将当前节点的线索标志位置为1
    }
    
    *prev = root;
}

int main() {
    // 创建二叉树
    Node* root = createNode(1);
    root->left = createNode(2);
    root->right = createNode(3);
    root->left->left = createNode(4);
    root->left->right = createNode(5);
    
    // 先序线索化
    Node* prev = NULL;
    preorderThreading(root, &prev);
    
    // 中序线索化
    prev = NULL;
    inorderThreading(root, &prev);
    
    // 后续线索化
    prev = NULL;
    postorderThreading(root, &prev);
    
    return 0;
}

回顾重点,其主要内容整理成如下内容:   

堆的定义及其建立

堆是一种特殊的完全二叉树,它具有以下两个特性: 

1)堆中任意节点的值都必须满足堆的性质:对于大根堆(或最大堆),每个节点的值都大于等于其子节点的值;对于小根堆(或最小堆),每个节点的值都小于等于其子节点的值。

2)堆中的二叉树总是完全填满的,即除了最后一层,其他层都是满的,且最后一层从左到右连续。

举个例子:

一个堆可以用一个一维数组来描述:

自顶向下建堆法:方法通过插入堆然后通过上滤方式(下与上比较,下比上大,下与上互换位置):

自下而上建堆法:方法是对每个父结点进行下滤(上与下比较,上比下大,上与下互换位置):

树与森林

树的存储表示

双亲表示法(顺序存储):用一个一维数组来存储树的所有节点,同时利用另外一个一维数组来存储每个节点的双亲节点。使用顺序存储双亲表示法时,可以方便地通过节点的下标查找其双亲节点,也可以根据节点的双亲节点编号快速查找该节点在数组中的位置。但是,插入和删除操作相对较为复杂,需要进行元素的移动,而且相比链式存储,需要额外的空间存储双亲节点编号信息。

如果想增一个数据结点,我们只需要在空白的位置写入这个结点,并且记录其与双亲结点的关系:

如果想删除一个结点可以采用以下两种方式。

方案一:删除的元素的双亲结点设为-1,表示该位置是空的

方案二:把尾部的元素填充到删除的结点上面:

如果删除的是一个父结点,需要查找其下面所有子孙节点并全部删除,如果之前采用过方案一的方式的话会导致会多遍历一个空数据从而导致遍历的速度变慢:

孩子表示法(顺序+链式存储):使用顺序存储孩子表示法时,可以通过节点的指针或索引直接访问其孩子节点,不需要遍历整个数组。对于叶子节点,可以使用特殊值(如-1)表示没有孩子节点。相比于双亲表示法,顺序存储孩子表示法节省了存储空间。

孩子兄弟表示法(链式存储): 孩子兄弟表示法适用于表示一般的树结构,而不仅限于二叉树。它节省了存储空间,并提供了一种紧凑且高效的方式来表示树。这种表示法常用于一些树的应用,如表达式树、文件系统的目录结构等。同时,由于链式结构的特性,插入和删除节点也相对较容易。

树和二叉树的相互转化:

森林与二叉树的转换

森林转换为二叉树的方式:左序列是父子关系、右序列是兄弟关系。具体转换如下:

回顾重点,其主要内容整理成如下内容:   

树和森林的遍历

树的先根遍历:

树的后根遍历:

树的层次遍历:

森林的先序遍历:

森林的中序遍历:

霍(哈)夫曼树

了解概念

结点的权:有某种现实含义的数值(如:表示结点的重要性等)

结点的带权路径长度:从树的根到该结点的路径长度(经过的边数)与该结点上权值的乘积:

举出以下的例子进行相应说明:

注意:在含有n个带权叶结点的二叉树中,其中带权路径长度(WPL)最小的二叉树称为哈夫曼树,也称最优二叉树。 因此我们可以根据这个特点对哈夫曼树进行构造:

哈夫曼编码

回顾重点,其主要内容整理成如下内容:    

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PHP会话技术跟踪和记录用户?使用cookie会话你必须掌握

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《速学数据结构》 《C语言进阶篇》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 &#x1f4cb; 前言会话技术的概述一. Cookie简介二. Cookie基本使用——创建Cookie2.1 创建Cookie演示实例&am…

Zinquin ethyl ester(CAS NO. 181530-09-6),TSQ的类似物

Zinquin ethyl ester&#xff08;CAS NO. 181530-09-6&#xff09;&#xff0c;是广泛使用锌离子荧光探针TSQ的类似物&#xff0c;也是一种细胞渗透性、基于喹诺酮结构的锌离子&#xff08;Zn2&#xff09;荧光探针&#xff0c; 该探针可以用于在细胞中检测和定位锌离子。它具…

软件公司的项目管理软件选择指南

我们经常在项目推进中经常遇到各种各样的问题&#xff0c;最常见的是因团队工作效率低而无法在截止日期之前按时完成工作。但是如果能合理使用项目管理软件&#xff0c;可以有效监控项目进程&#xff0c;提高工作效率&#xff0c;从而保证按时完成任务。那么软件公司适合什么项…

Qt编程-QTableView同时冻结行和列

前言 Qt编程-QTableView同时冻结行和列。如题&#xff0c;先看效果是不是你需要的。网上找到的代码片段要么不全要么不是想要的。如果你只需要需要冻结行或冻结列&#xff0c;请看上篇博客 Qt编程-QTableView冻结行或冻结列或冻结局部单元格 &#xff0c;代码更少一些。 同时…

ansible 调研

参考&#xff1a;自动化运维工具——ansible详解&#xff08;一&#xff09; - 珂儿吖 - 博客园 (cnblogs.com) ansible是新出现的自动化运维工具&#xff0c;基于Python开发&#xff0c;集合了众多运维工具&#xff08;puppet、chef、func、fabric&#xff09;的优点&#xf…

专用/独享代理与共享代理有何区别?如何选择?

近年来&#xff0c;互联网发展快速&#xff0c;随着许多互联网业务的迸发&#xff0c;代理IP也作为一种互联网工具进入大家的业务&#xff0c;广泛地运用于跨境电商、社媒运营、SEO检测、市场研究等业务中。那么代理IP分为共享与独享&#xff0c;他们使用上有什么区别&#xff…

让你的对象变得拗口:JSON.stringify(),我把对象夹进了 JSON 魔法帽!

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 引言 1. JSON.stringify() 属性 replacer …

Gartner中国零信任网络访问市场指南发布!持安科技获评代表厂商

近日&#xff0c;全球权威市场研究与咨询机构Gartner发布《中国零信任网络访问市场指南》。其中&#xff0c;零信任办公安全企业持安科技入选为中国零信任网络访问领域“代表厂商”。 市场指南报告&#xff08;Market Guide&#xff09;是Gartner基于技术发展、落地案例等进行严…

Linux 实时补丁开启内核抢占了吗?

Linux 实时补丁开启内核抢占了吗&#xff1f; 开启了。 查看Linux实时补丁&#xff0c;发现修了如下内核宏&#xff1a; PREEMPT_RT补丁的关键点是最小化不可抢占的内核代码量&#xff0c;同时最小化为了提供这种额外的可抢占性而必须更改的代码量。特别是&#xff0c;临界区…

深度学习DAY3:激活函数

激活函数映射——引入非线性性质 h &#xff08;Σ(W * X)b&#xff09; yσ&#xff08;h&#xff09; 将h的值通过激活函数σ映射到一个特定的输出范围内的一个值&#xff0c;通常是[0, 1]或[-1, 1] 1 Sigmoid激活函数 逻辑回归LR模型的激活函数 Sigmoid函数&#xff0…

竞赛 深度学习 大数据 股票预测系统 - python lstm

文章目录 0 前言1 课题意义1.1 股票预测主流方法 2 什么是LSTM2.1 循环神经网络2.1 LSTM诞生 2 如何用LSTM做股票预测2.1 算法构建流程2.2 部分代码 3 实现效果3.1 数据3.2 预测结果项目运行展示开发环境数据获取 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天…

Bootstrap中让元素尽可能往父容器的左侧靠近或右侧造近(左浮动和右浮动)

在Bootstrap中&#xff0c;float-left是一个用于浮动元素的CSS类。它的作用是将一个元素向左浮动&#xff0c;使其在父容器内尽可能靠近左侧边缘&#xff0c;同时允许其他元素在其右侧排列。 使用float-left类可以创建多列布局&#xff0c;将元素水平排列在一行上&#xff0c;…

【脑机接口论文与代码】High-speed spelling with a noninvasive brain–computer interface

High-speed spelling with a noninvasive brain–computer interface 中文题目 &#xff1a;非侵入性的高速拼写脑机接口论文下载算法程序下载摘要1 项目介绍2 方法2.1SSVEPs的基波和谐波分量JFPM刺激产生算法2.3基波和谐波SSVEP分量的幅度谱和信噪比 3讨论4实验环境设置与方法…

全球邮企业邮箱服务比较:找寻最佳选择

“全球邮企业邮箱服务比较&#xff1a;Gmail、Outlook、Yahoo Mail、Zoho Mail&#xff0c;更适合中国用户的是Zoho Mail。” 在全球化的商业环境中&#xff0c;企业邮箱已经成为了一种重要的沟通工具。它不仅提供了安全、可靠的电子邮件服务&#xff0c;而且还能够集成其他企业…

hive add columns 后查询不到新字段数据的问题

分区表add columns 查询不到新增字段数据的问题&#xff1b; 5.1元数据管理 &#xff08;1&#xff09;基本架构 Hive的2个重要组件&#xff1a;hiveService2 和metastore,一个负责转成MR进行执行&#xff0c;一个负责元数据服务管理 beeline-->hiveService2/spar…

性能分析与调优(硬核分享)

前言 常看到性能测试书中说&#xff0c;性能测试不单单是性能测试工程师一个人的事儿。需要DBA 、开发人员、运维人员的配合完成。但是在不少情况下性能测试是由性能测试人员独立完成的&#xff0c;退一步就算由其它人员的协助&#xff0c;了解系统架构的的各个模块对于自身的…

MAX4/11/03/016/08/1/1/00 MAX-4/11/01/008/08/1/1/00

MAX4/11/03/016/08/1/1/00 MAX-4/11/01/008/08/1/1/00 sales force宣布推出制造业云(Manufacturing Cloud)&#xff0c;这是一款面向制造商的行业专用产品。制造云致力于将销售和运营团队聚集在统一的市场和客户需求视图周围&#xff0c;目标是更准确地预测、规划和推动可预测…

口袋参谋:如何对宝贝关键词进行词根分析?用它就对了!

​为什么宝贝转化不好&#xff1f;90%的原因是宝贝关键词没选好&#xff0c;关键词选择得不好&#xff0c;会出现点击率、展现、访客、收藏加购率等数据降低的情况&#xff0c;还会导致关键词质量得分波动大&#xff0c;甚至影响整个店铺的经营。 所以对电商卖家来说&#xff…

微信照片过期打不开怎么办?用这个办法可找回

时间太久想找之前的聊天图片 却发现图片已被清理 因为忙碌或者在外游玩一时间忘了点开 想起要找回的时候却发现已经过期 不妨试试这样几个找回小方法 PART2 图片找回 收藏和搜一搜找回 长按要找回的图片 点击收藏或搜一搜 不能保证百分百的成功率哦 存储空间找回 打开【存…

性能测试-如何进行监控设计

监控设计步骤 首先&#xff0c;你要分析系统的架构。在知道架构中使用的组件之后&#xff0c;再针对每个组件进行监控。 其次&#xff0c;监控要有层次&#xff0c;要有步骤。先全局&#xff0c;后定向定量分析。 最后&#xff0c;通过分析全局、定向、分层的监控数据做分析…