线索二叉树构造及遍历算法
线索二叉树构造以及遍历算法
- 线索二叉树(中序遍历版)
- 构造线索二叉树
- 构造双向线索链表
- 遍历中序线索二叉树
线索二叉树(中序遍历版)
中序遍历找到对应结点的前驱(土方法)
typedef struct BiNode{int data;BiNode *lchild, *rchild;
}BiNode, *BiTree;BiNode *p; // 指向目标节点
BiNode *pre = NULL; // 指向当前访问节点的前驱
BiNode *final = NULL; // 记录最终结果void InOrder(BiTree T){if(T != NULL){InOrder(T -> lchild);visit(T);InOrder(T -> rchild);}
}// 找到目标节点的前驱节点
void visit(BiNode *q){ // q代表当前访问节点if(p == q)final = pre; // 如果当前访问节点和目标节点一致了,那么pre就是我们需要找的前驱elsepre = q; // 如果不一致,那么更新前驱节点
}
由上述代码我们可以知道,如果使用土方法来寻找目标节点的前驱节点,那么每找一次,就需要对二叉树进行一次遍历,这样对资源的浪费是不言而喻的,所以我们需要采用线索二叉树来更加快速地寻找对应节点的前驱后继,通过线索二叉树,我们可以实现对二叉树的随机访问。
问题1:为什么在visit函数中不需要对q进行迭代?
回答1:因为 q q q的迭代是在 I n O r d e r InOrder InOrder中进行的,在每一次对 I n O r d e r InOrder InOrder的递归中,传入 v i s i t visit visit的节点会不会·不断变化,也就实现了对 q q q的迭代。
线索二叉树实际就是用空的 n + 1 个空指针指向直接前驱和直接后继。如果一个节点的左孩子为空,则左孩子指针指向当前节点的前驱,改 l t a g ltag ltag为1;如果一个节点的右孩子为空,则用右孩子指针指向当前节点的后继,改 r t a g rtag rtag为1。
lchild | ltag | data | rtag | rchild |
---|---|---|---|---|
指示左孩子 | 0 | 0 | 指示右孩子 | |
指示直接前驱 | 1 | 1 | 指示直接后继 |
// 线索二叉树的存储结构
typedef struct ThreadTree{int data;struct ThreadTree *lchild, *rchild;int ltag, rtag;
}ThreadNode, *ThreadTree;
构造线索二叉树
通过中序遍历对二叉树线索化
void InThread(ThreadTree &p, ThreadTree &pre){ // p是当前访问节点,pre为当前访问节点的前驱if(p != NULL){InThread(p -> lchild);if(p -> lchild == NULL){ // 如果左孩子为空,则更新左孩子为前驱,ltag为1p -> lchild = pre;ltag = 1;}if(pre != NULL && pre -> rchild == NULL){ // 若前驱节点非空且其右子树为空,则更新其右孩子为后继,rtag为1pre -> rchild = p;pre -> rtag = 1;}pre = p;InThread(p -> rchild);}
}
void CreateInThread(ThreadTree T){Thread pre = NULL;if(T != NULL){InThread(T, pre);pre -> rchild = NULL; // 处理最后一个节点pre -> rtag = 1;}
}
问题2:为什么在创建二叉树的时候需要判断pre是否为空?
回答2:为了避免空指针引用,我们在创建线索二叉树的时候,会把pre初始化为NULL(也就是其实并没有这个节点),因为第一个节点没有直接的前驱,而如果我们不对空指针进行判断的话,那么pre的后继就会是当前节点p,那么究竟谁才是第一个节点呢?运行起来就会导致程序崩溃。只有当pre不为空时,才有意义去判断其右子树是否为空,为它建立线索二叉树才有意义。
构造双向线索链表
但是这样的线索二叉树还是存在一些问题,比如没有办法从第一个节点直接遍历到最后一个节点,为此我们可以建立一个头节点,让其lchild
指向二叉树的根节点,其rchild
指向中序遍历时访问的最后一个节点。令中序遍历的第一个节点的lchild
指向头节点,也就是第一个节点的前驱不再是NULL
,而是head
;令中序遍历的最后一个节点的rchild
指向头节点,也就是最后一个节点的后继也不再是NULL
,而是head
。这样一来,我们就获得了一个双向线索链表。
void InThread(ThreadTree &p, ThreadTree &pre){ // p是当前访问节点,pre为当前访问节点的前驱if(p != NULL){InThread(p -> lchild);if(p -> lchild == NULL){ // 如果左孩子为空,则更新左孩子为前驱,ltag为1p -> lchild = pre;ltag = 1;}if(pre != NULL && pre -> rchild == NULL){ // 若前驱节点非空且其右子树为空,则更新其右孩子为后继,rtag为1pre -> rchild = p;pre -> rtag = 1;}pre = p;InThread(p -> rchild);}
}
void CreateInThread(ThreadTree T){ThreadNode *head = (ThreadTree*)malloc(sizeof(ThreadTree));if(head == NULL)return ;head -> ltag = 0; // 指向根节点head -> rtag = 1; // 指向最后一个节点head -> rchild = head; // 初始化右指针指向自己if(T == NULL){head -> lchild = head;}else {head -> lchild = T;ThreadTree pre = head;InTread(T, pre);// 处理最后一个节点pre -> rchild = head;pre -> rtag = 1;// 处理第一个节点ThreadNode *first = head -> lchild; // 初始化第一个节点为根节点,方便找到第一个节点// 寻找中序遍历的第一个节点while(first -> ltag == 0) // 如果lchild是指向左孩子则迭代first = first -> lchild;first -> lchild = head;}
}
遍历中序线索二叉树
只要先找到序列中的第一个节点,然后依次找节点的后继,直到其后继为空便可完成遍历;
1. 求第一个节点
ThreadNode *FirstNode(ThreadNode *p){while(p -> ltag == 0) p = p -> lchild;return p;
}
2. 求中序线索二叉树中节点p在中序序列下的后继
ThreadNode *NextNode(ThreadNode *p){if(p -> rtag == 0) return FirstNode(p -> rchild); // 右子树中最左下节点else return p -> rchild;
}
3. 求中序线索二叉树的最后一个节点
ThreadNode *LastNode(ThreadNode *p){while(p -> rtag == 0) p = p -> rchild;return p;
}
4. 求节点p前驱
ThreadNode *PreNode(ThreadNode *p){if(p -> ltag == 0) return LastNode(p -> lchild);return p;
}
利用上述1.2.两个算法,我们可以写出不含头节点的中序线索二叉树的中序遍历算法:
void InOrder(ThreadNode *T){for(ThreadNode *p = FirstNode(T); p != NULL; p = NextNode(p))visit(p); // 访问节点,可自由设定
}
相关文章:
线索二叉树构造及遍历算法
线索二叉树构造以及遍历算法 线索二叉树(中序遍历版)构造线索二叉树构造双向线索链表遍历中序线索二叉树 线索二叉树(中序遍历版) 中序遍历找到对应结点的前驱(土方法) #mermaid-svg-eunGO5d2GhjLxCn5 {fo…...
3. 自定义类型****
目录 1. 内存对齐(必考) 如何计算? 为什么要内存对齐? 2. 联合 2.1 联合的定义 2.2 联合的特点 1. 内存对齐(必考) 结构体内存对齐是一个特别热门的考点。 如何计算? 第一个成员在与结构…...
Redis Sentinel (哨兵模式)深度解析:构建高可用分布式缓存系统的核心机制
一、传统主从复制的痛点 在分布式系统架构中,Redis 作为高性能缓存和数据存储解决方案,其可用性直接关系到整个系统的稳定性。传统的主从复制架构虽然实现了数据冗余,但在面临节点故障时仍存在明显缺陷: 手动故障转移…...
deepseek本地部署
deepseek本地部署 哈喽,兄弟们!大家可以想象一下,如果有一个超级聪明的人机大脑,能帮你解答任何问题,从复杂的数学难题到编程代码,再到那些让你头疼的写作任务,它都能轻松搞定。这不是科幻电影里的场景,而是DeepSeek带来的现实奇迹!DeepSeek,这个名字听起来就充满了…...
责任链模式的C++实现示例
核心思想 责任链模式是一种行为设计模式,允许多个对象都有机会处理请求,从而避免请求的发送者与接收者之间的耦合。请求沿着处理链传递,直到某个对象处理它为止。 解决的问题 解耦请求发送者与处理者:请求的发送者无需知道具…...
【蓝桥杯python研究生组备赛】003 贪心
题目1 股票买卖 给定一个长度为 N 的数组,数组中的第 i 个数字表示一个给定股票在第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 注意:你不能同时参与多笔交易&…...
Banana Pi 与瑞萨电子携手共同推动开源创新:BPI-AI2N
2025年3月11日, Banana Pi 开源硬件平台很高兴宣布,与全球知名半导体解决方案供应商瑞萨电子(Renesas Electronics)正式达成技术合作关系。此次合作标志着双方将在开源技术、嵌入式系统和物联网等领域展开深度合作,为全…...
【算法工具】HDL: 基于摘要统计数据的高维连锁不平衡分析软件
## 前言 在基因组研究中,连锁不平衡(Linkage Disequilibrium, LD)分析是理解遗传变异之间关联的关键步骤。然而,当面对高维数据时,传统分析方法往往面临巨大计算挑战。今天为大家介绍一款强大的工具——HDL (High-Dimensional Linkage diseq…...
虚拟展览馆小程序:数字艺术与文化展示的新形式探索
虚拟展览馆小程序:数字艺术与文化展示的新形式探索 一、传统展览的痛点:物理空间的局限与数字化的必然 在传统的艺术与文化展览中,观众往往需要跨越地理距离、排队数小时才能进入展馆,而许多珍贵展品因保护需求无法长期展出。数据显示,全球90%以上的博物馆藏品常年沉睡于…...
docker 搭建alpine下nginx1.26/mysql8.0/php7.4环境
docker 搭建alpine下nginx1.26/mysql8.0/php7.4环境 docker-compose.yml services:mysql-8.0:container_name: mysql-8.0image: mysql:8.0restart: always#ports:#- "3306:3306"volumes:- ./etc/mysql/conf.d/mysql.cnf:/etc/mysql/conf.d/mysql.cnf:ro- ./var/log…...
java项目之基于ssm的在线学习系统(源码+文档)
项目简介 在线学习系统实现了以下功能: 该系统可以实现论坛管理,通知信息管理,学生管理,回答管理,教师管理,教案管理,公告信息管理,作业管理等功能。 💕💕作…...
macOS 安装配置 iTerm2 记录
都说 macOS 里替换终端最好的就是 iTerm2 ,这玩意儿还是开源的,所以就也根风学习一下,但全是英文的挺麻烦,所以这里记录一下自己的设置,以最简单的安装及设置为主,想要更酷炫、更好看的还请自己百度吧&…...
矩阵分析-浅要理解(深度学习方向)
梯度分析与最优化 在深度学习的任务中,我们所期望的是训练一个神经网络,使得预测结果与真实标签之间的误差最小化,这可以近似看作是一个提供梯度下降等优化找到全局最优解的凸优化问题。 奇异值分解 在信息工程领域,对数据处理的…...
Odoo 18 中的自动字段和预留字段
Odoo 18 中的自动字段和预留字段 作为一个开源平台,Odoo 的价值在于其使用和开发的灵活性、可扩展性和经济性。虽然 Odoo 本身主要用 Python 和 JavaScript 编写,但其作为开源 ERP 系统的价值超越了特定编程语言的范畴,为各行各业的企业提供了…...
【操作系统安全】任务1:操作系统部署
目录 一、VMware Workstation Pro 17 部署 二、VMware Workstation 联网方式 三、VMware 虚拟机安装流程 四、操作系统介绍 五、Kali 操作系统安装 六、Windows 系统安装 七、Windows 系统网络配置 八、Linux 网络配置 CSDN 原创主页:不羁https://blog.csd…...
Linux:自动化构建-make/Makefile
1.背景 一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作…...
maven wrapper的使用
写在前面 考虑这样的场景,张三创建了一个maven项目使用了3.9版本,当李四下载下来去开发配置的却是3.6版本,此时李四就不得不再去配置一个3.9版本的maven,为了解决这个问题,maven引入了maven wrapper的机制(…...
DB-GPT-0.7版本win11安装,最新版本,安装方式变更了
之前两天折腾要死,只因为安装了旧版本问题太多,现在安装最新版本 快速开始_V0.7.0 语雀 DB-GPT 0.7.0 部署教程 - yyhhyys blog DB-GPT 0.7.0 与 DeepSeek 集成使用指南 - yyhhyys blog 首先代码结构换了,python包管理工作也换了…...
树莓集团落子海南,如何重构数字产业生态体系
树莓集团在海南的布局,是其整体商业战略中的关键一环。这背后,是对政策机遇、产业协同、以及区域优势的深度考量。 政策机遇 海南自贸港建设带来前所未有的政策红利,包括贸易、投资、资金等方面的自由便利。树莓集团紧抓这一机遇࿰…...
Spring Boot 项目部署启动异常问题分析与解决:主类缺失与依赖冲突的分析
Spring Boot 项目部署启动异常问题分析与解决 在近期的 Spring Boot 项目部署工作中,遭遇了一起典型的启动异常状况。经过多维度的深入排查以及细致的调试,最终确定问题的根源在于打包插件配置与依赖管理的综合影响。以下将详细阐述整个问题的分析过程以及对应的解决办法。 …...
共享内存(System V)——进程通信
个人主页:敲上瘾-CSDN博客 进程通信: 匿名管道:进程池的制作(linux进程间通信,匿名管道... ...)-CSDN博客命名管道:命名管道——进程间通信-CSDN博客 目录 一、共享内存的原理 二、信道的建立 …...
考研数学非数竞赛复习之Stolz定理求解数列极限
在非数类大学生数学竞赛中,Stolz定理作为一种强大的工具,经常被用来解决和式数列极限的问题,也被誉为离散版的’洛必达’方法,它提供了一种简洁而有效的方法,使得原本复杂繁琐的极限计算过程变得直观明了。本文&#x…...
12 DHCP的内容和HTTP的改良
一、回顾 计算机分配相关身份 网络号、主机号 网络号内的主机识别 局部网通信网关 不同网络的通信DNS服务器 域名解析 因特网通信 二、DHCP协议 建议学习前看这个视频,14分钟,所有的知识点都有,很容易理解 1、理解 DHCP 的全称是 Dynam…...
多光谱相机数据采集过程中常见仪器
1.BF1515多光谱相机 2.VIX-N220推扫式可见光近红外高光谱相机 覆盖光谱范围:400-1000nm; 光谱分辨率:2nm; 设备配套软件:VIX-N220、XuanDo(用于调节相机推扫速度); 镜头调节所需材料:黑色条…...
【调研】olmOCR解析PDF
测试用例: olmOCR GOT-OCR 将最底下没有文字的部分,可能是样式解析出重复 olmOCR GOT-OCR 无重复 重复 速度上,olmOCR效果更快 效果上,olmOCR解析得到的内容排版更加清晰整齐,而且对于6份GOT-OCR有重复的测…...
蓝桥杯随笔练——二分模板
答案 #include <bits/stdc.h> //洛谷2249 using namespace std;const int N 1e610; int n,m; int a[N];int Array_Search(int a[],int len,int x) {int L 0,R len1;while(L1 < R){int mid (RL) >> 1;if(a[mid] < x ) L mid;else R mid;}if(a[R] x) r…...
【Golang】第三弹----运算符
笔上得来终觉浅,绝知此事要躬行 🔥 个人主页:星云爱编程 🔥 所属专栏:Golang 🌷追光的人,终会万丈光芒 🎉欢迎大家点赞👍评论📝收藏⭐文章 一、运算符介绍 运算符是一…...
MongoDB 聚合管道速成教程
一、引言 MongoDB 的聚合管道(Aggregation Pipeline)是一种强大的数据处理工具,它允许你对文档进行一系列的操作,如过滤、转换、分组和聚合等。聚合管道由多个管道组成,每个管道对输入的文档进行特定的处理࿰…...
「JavaScript深入」二进制数据处理详解「Blob、File、FileReader、ArrayBuffer、Typed Arrays、DataView」
二进制数据处理详解 1. Blob(Binary Large Object)Blob 的特性创建 BlobBlob 主要方法Blob 的应用 2. FileFile 对象的属性获取 File 对象 3. FileReader创建 FileReader主要方法主要事件文件上传与读取内容示例文件分块读取示例 4. ArrayBuffer 与 Type…...
信号处理之插值、抽取与多项滤波
信号处理之插值、抽取与多项滤波 一、问题背景 插值(Interpolation)与抽取(Decimation)是数字信号处理中采样率转换的核心操作: 插值:在信号中插入新样本以提高采样率( L L L倍)抽取:按比例 M M M降低采样率…...
关于WPS的Excel点击单元格打开别的文档的两种方法的探究
问题需求 目录和文件结构如下: E:\Dir_Level1 │ Level1.txt │ └─Dir_Level2│ Level2.txt│ master.xlsx│└─Dir_Level3Level3.txt现在要在master.xlsx点击单元格进而访问Level1.txt、Level2.txt、Level3.txt这些文件。 方法一:“单元格右键…...
蓝桥 2109统计子矩阵
问题描述 给定一个NM 的矩阵 A, 请你统计有多少个子矩阵 (最小 11, 最大 NM) 满足子矩阵中所有数的和不超过给定的整数 K ? 输入格式 第一行包含三个整数 N,M 和 K. 之后 NN 行每行包含 M 个整数, 代表矩阵 A. 输出格式 一个整数代表答案。 样例输入 3 4 10 1 2 3 4 5…...
AF3 make_fixed_size函数解读
AlphaFold3 data_transforms 模块的 make_fixed_size 函数的作用是将输入的蛋白质特征字典 protein 中的各个特征张量调整为固定大小。这是为了确保在批量处理时,所有特征张量的形状一致,从而避免形状不匹配的问题。 源代码: import itertools import torch from src.con…...
前端模块管理新思路:如何使用 Import Maps
前言 前端开发中,我们常常需要使用各种库和模块来构建功能丰富的应用。在传统方式中,管理这些库和模块的引用可能会有些繁琐。 幸运的是,Import Maps 的出现为我们提供了一种更简洁和高效的解决方案。今天我们就来聊聊如何使用 Import Maps。…...
交换机、路由器、网关、MAC地址——从入门到实战
你是否好奇,当你在手机上点击一个网页链接时,数据是如何从你的设备“飞”到千里之外的服务器并返回的?背后离不开交换机、路由器、网关和MAC地址的默契配合。本文用通俗语言实战场景,带你彻底搞懂这些网络核心组件,从此…...
【江协科技STM32】ADC数模转换器-学习笔记
ADC简介 ADC(Analog-Digital Converter)模拟-数字转换器ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁,ADC是一种将连续的模拟信号转换为离散的数字信号的设备或模块12位逐次逼近型…...
LanceDB快速入门之基本操作与API一览
LanceDB可以以多种方式运行 可以嵌入到现有后端(如您的 Django、Flask、Node.js 或 FastAPI 应用程序)中直接从如 Jupyter 笔记本等客户端应用程序中用于分析工作负载部署为远程无服务器数据库 安装 Python: pip install lancedbTypeScrip…...
Spring Boot 整合 Redis
以下是 Spring Boot 整合 Redis 的指南,涵盖配置、基本操作、高级用法及常见问题解决。 1. 添加依赖 在 pom.xml 中添加 Spring Data Redis 和连接池依赖: <dependency><groupId>org.springframework.boot</groupId><artifactId&…...
七层协议攻防实战:从HTTP慢速攻击到DNS隧道检测
一、七层协议攻击类型与特征 攻击类型协议特征HTTP慢速攻击HTTP低速率发送不完整请求DNS隧道DNS异常长域名、高频率TXT查询API滥用攻击HTTP高频调用关键接口(如短信发送)WebSocket洪水WebSocket海量小消息耗尽服务器资源 二、HTTP协议深度防护 1. 慢速…...
Java CAS(Compare-And-Swap)概念及原理
Java CAS(Compare-And-Swap)概念及原理 1. CAS的基本概念 CAS(Compare-And-Swap)是一种无锁编程的核心技术,用于实现多线程环境下的原子操作。其核心思想是: “先比较,再交换”。具体操作包含…...
内存检测工具——Qt Creator
前言 检测内存错误的工具,有很多个,我今天粗浅的学了一下可在Qt上使用的工具们: Dr.Memory 工具之前我曾在关注的博主上看到相关的博客:C(Qt)软件调试---内存调试器Dr.Memory(21)_dr. memory-CSDN博客 今…...
Ubuntu切换lowlatency内核
文章目录 一. 前言二. 开发环境三. 具体操作 一. 前言 低延迟内核(Lowlatency Kernel) 旨在为需要低延迟响应的应用程序设计的内核版本。Linux-lowlatency特别适合音频处理、实时计算、游戏和其他需要及时响应的实时任务。其主要特点是优化了中断处理、调…...
侯捷 C++ 课程学习笔记:STL标准库与泛型编程
STL 体系结构基础介绍 STL 六大部件: 容器(Containers) 分配器(Allocators) …...
Java 大视界 -- Java 大数据在智能安防视频摘要与检索技术中的应用(128)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...
19874并查集
19874并查集 ⭐️难度:中等 🌟考点:并查集、数据结构 📖 📚 import java.util.*;public class Main {static int N 100010;static int[] a new int[N];static int[] p new int[N];static int n;static int m;st…...
ABC 376
目录 D. Cycle D. Cycle(改) E. Max Sum D. Cycle 这道题就是个 01 最短路,直接从 1 开始 bfs 看能不能回到 1 #include<bits/stdc.h> #define int long long using namespace std; const int N 2e5 5, INF 1e18;struct node {int …...
win32汇编环境,对 WM_MOUSEMOVE 消息的理解
;运行效果 ;win32汇编环境,对 WM_MOUSEMOVE 消息的理解 ;理解在 WM_MOUSEMOVE 消息发生时,同时来的wParam和lParam值的含义,并取出各自的值进行运用。从这例子也可以更好的理解windows的消息机制. ;WM_MOUSEMOVE消息就是当鼠标移动时,发送给窗…...
第27周JavaSpringboot电商进阶开发 2.常用功能进阶
电商常用功能进阶 - 课程笔记整理 Excel解析与处理 一、课程内容概述 本小节开始进入电商常用功能进阶部分,主要讲解以下内容: Excel的解析和处理商品图片的处理Valid注解对列表的验证订单数变化趋势图Spring Boot高级功能 二、Excel解析与处理的背…...
网络安全基础知识:从零开始了解网络安全
### 网络安全基础知识:从零开始了解网络安全 欢迎来到《零基础入门到独立参加网络安全比赛》系列教程的第一篇!在这篇文章中,我们将从最基础的概念开始,深入探讨网络安全的定义、重要性、常见的网络攻击类型,以及网络…...
【A2DP】蓝牙A2DP协议剖析:从架构到规范
目录 一、A2DP 协议架构 1.1 A2DP 协议栈结构组成 1.2 协议栈各部分的关系与作用 二、设备配置与角色定义(Configurations and roles ) 2.1 角色定义 2.2 配置示例与角色体现 三、用户需求与场景 3.1 用户需求与场景 3.2 协议限制 3.3 协议要求…...