当前位置: 首页 > news >正文

线索二叉树结构

线索二叉树结构

  • 1.线索二插树的作用
  • 2.线索二叉树的定义
  • 3.线索二叉树的结构
  • 4. 线索二叉树的操作
    • 4.1. 建立一棵中序线索二叉树
    • 4.2. 在中序线索二叉树上查找任意结点的中序前驱结点
    • 4.3. 在中序线索二叉树上查找任意结点的中序后继结点
    • 4.4. 在中序线索二叉树上查找任意结点在先序下的后继结点
    • 4.5. 在中序线索二叉树上查找任意结点在后序下的前驱结点
    • 4.6. 在中序线索二叉树上查找值为x的结点
    • 4.7. 中序线索二叉树上的插入与删除
  • 5. 基于中序线索二叉树的遍历算法

1.线索二插树的作用

通过递归算法或者是用栈与队列实现非递归算法都会有额外空间上的开销。利用n个结点有n+1个空指针域来存放线索,然后利用这个线索来实现不用空额外空间来遍历二叉树。

2.线索二叉树的定义

在某种顺序遍历二叉树的时候,存在直接前驱结点和后继结点的信息,对于非空指针域指向原本的左右孩子,而对于非空指针域来说,左孩子指针指向遍历序列的直接前驱结点,右孩子指向遍历序列的直接后继结点。
这种指针称为线索,加了线索的二叉树称为线索二叉树。

3.线索二叉树的结构

为每个结点增设两格标志域ltag和rtag,令:
当Itag=0:表示lchild指向结点的左孩子;ltag=1:表示lchild指向结点的前驱结点。
当rtag=0:表示rchild指向结点的右孩子;rtag=1:表示rchild指向结点的后继结点。

为了将二叉树的所有空指针域都利用上,并且方便判断遍历操作何时结束,在存储的时候增设一个头结点,该头结点和其他结点类型相同,值域不存储值,初始化使其左指针域指向二叉树的根结点,右指针域指向自己。线索化完成后,让头结点的值域指向按某种顺序 遍历下的最后一个结点。而原二叉树在某种遍历顺序下的第一个结点的前驱线索和最后一个结点的后继线索都指向。
【结构体的定义】

//线索二叉树结点的定义
typedef char ElemType;
typedef struct BiThrNode
{ElemType data;int ltag;int rtag;struct BiThrNode* lchild;struct BiThrNode* rchild;
}BiThrNode,*BiThrTree;

4. 线索二叉树的操作

4.1. 建立一棵中序线索二叉树

【算法实现】

//建立中序线索二叉树
void InThreading(BiThrTree p, BiThrTree* pre)//递归算法
{if (p){InThreading(p->lchild, pre);//左子树线索化//前驱线索if (!p->lchild){p->ltag = 1;p->lchild = *pre;}elsep->ltag = 0;//后继线索if (!(*pre)->rchild){(*pre)->rtag = 1;(*pre)->rchild = p;}else(*pre)->rtag = 0;*pre = p;InThreading(p->rchild, pre);//右子树的线索化}
}
int InOrderThr(BiThrTree* head, BiThrTree T)//带头结点的中序线索二叉树的算法
{//基于中序遍历二叉树T,并将中序线索化,*head指向头结点//申请头结点的空间BiThrTree pre;if (!(*head = (BiThrTree)malloc(sizeof(BiThrNode))))return 0;//建立头结点(*head)->ltag = 0;(*head)->rchild = *head;//右指针回针if (!T)(*head)->lchild = *head;//若二叉树为空,则左指针回针else{(*head)->lchild = T;pre = *head;InThreading(T, &pre);//中序遍历进行中序线索化pre->rchild = *head; pre->rtag = 1;//最后一个结点线索化(*head)->rtag = 1;(*head)->rchild = pre;}return 1;
}

4.2. 在中序线索二叉树上查找任意结点的中序前驱结点

存在两种情况:

  1. 如果该结点的左标志为1,那么其左指针域指向的结点就是它的前驱结点。
  2. 如果该结点的左标志为0,那么说明该结点存在左孩子。由中序序列的定义,该左孩子的右子树的最后一个结点就是该结点前驱结点。即沿着其左孩子右指针向下找,当某个结点的右标志域为1时,它就是该结点的前驱结点。

【算法实现】

//在中序线索二叉树上查找任意结点的中序前驱结点
BiThrTree InPreNode(BiThrTree p)
{//在中序线索二叉树上寻找结点p的中序前驱结点BiThrTree pre = p->lchild;if (p->ltag == 0)//有左子树,找左子树最右下方的结点{while (pre->rtag == 0)pre = pre->rchild;}return pre;
}

4.3. 在中序线索二叉树上查找任意结点的中序后继结点

  1. 如果该结点的右标志为1,那么其右指针域指向的结点就是它的后继结点。
  2. 如果该结点的右标志为0,那么说明该结点存在右孩子。由中序序列的定义,该右孩子的左子树的最后一个结点就是该结点后继结点。即沿着其右孩子左指针向下找,当某个结点的左标志域为1时,它就是该结点的后继结点。

【算法实现】

//在中序线索二叉树上查找任意结点的中序后继结点
BiThrTree InPostNode(BiThrTree p)
{//在中序线索二叉树上寻找结点p的中序后继结点BiThrTree post = p->rchild;if (post->rtag == 0)//有右子树,找右子树最左下方的结点{while (post->ltag == 0)post = post->lchild;}return post;
}

4.4. 在中序线索二叉树上查找任意结点在先序下的后继结点

(1)若 * p为分支结点,待确定的先序下的后继结点有两种情况
①当p->ltag=0时,* p的左孩子为 * p的先序下的后继结点。
②当p->ltag=1且 p->rtag=0时,* p 的右孩子为 * p先序下的后继结点
(2)若 * p为叶子结点:
如果 * p的后继结点存在,则说明 一定是 * p某个祖先的右孩子结点;不存在则指向头结点。
【算法实现】

//在中序线索二叉树上查找任意结点在先序下的后继结点
BiThrTree InPrePostNode(BiThrTree head, BiThrTree p)
{//在中序线索二叉树上寻找结点p的先序下的后继结点,head为头结点BiThrTree post;if (p->ltag == 0)post = p->lchild;//*p有左子树else{post = p;while (post->rtag == 1 && post->rchild != head)post = post->rchild;post = post->rchild;}return post;
}

4.5. 在中序线索二叉树上查找任意结点在后序下的前驱结点

两种情况:
①存在右孩子,则右孩子是后序下的前驱结点;存在左孩子但是不存在右孩子,则左孩子是后序的前驱结点。
②是叶子结点,则它的在后序下的前驱结点是其某个祖先的左孩子,或者不存在则是头结点。
【算法实现】

//在中序线索二叉树上查找任意结点在后序结点下的前驱结点
BiThrTree InPostPreNode(BiThrTree head, BiThrTree p)
{//在线索二叉树上寻找结点p的后序下的前驱结点,head为头结点BiThrTree pre;if (p->rtag == 0)pre = p->rchild;else{pre = p;while (pre->ltag == 1 && pre->lchild != head)pre = pre->lchild;pre = pre->lchild;}return pre;
}

4.6. 在中序线索二叉树上查找值为x的结点

先找打中序序列中的第一个结点,在依次往后遍历整个中序线索二叉树。
【算法实现】

//在中序线索二叉树上查找值为x的结点
BiThrTree Search(BiThrTree head, ElemType x)
{//以head的头结点的中序线索二叉树中查找值为x的结点BiThrTree p = head->lchild;while (p->ltag == 0 && p != head)p = p->lchild;//找到中序序列的第一个结点while (p != head && p->data != x)p = InPostNode(p);if (p == head){printf("Not Found the data!\n");return 0;}else return p;
}

4.7. 中序线索二叉树上的插入与删除

插入和删除一个结点,都需要重新进行线索化。在这里讨论,插入一个结点使其成为右孩子。
【算法实现】

//在中序线索二叉树上的插入与删除
void InsertThrRight(BiThrTree s, BiThrTree p)
{//在中序线索二叉树中插入结点p,使其称为结点s的右孩子BiThrTree w;//将s变为p的中序前驱p->rchild = s->rchild;p->rtag = s->rtag;p->lchild = s;p->ltag = 1;//p变成s的右孩子s->rchild = p;s->rtag = 0;//当前s原来的右子树不为空,找到s的后继w,将w变成p的后继,并将p变成w的前驱if(p->rtag==0){w = InPostNode(p);w->lchild = p;}
}

5. 基于中序线索二叉树的遍历算法

//基于中序线索二叉树的遍历算法
void ThInOrder(BiThrTree head)
{//在中序线索二叉树上进行中序遍历BiThrTree p = head->lchild;while (p->ltag == 0)p = p->lchild;//找第一个结点while (p != head)//依序找后继结点{printf("%c ", p->data);p = InPostNode(p);}
}
void ThpreInOrder(BiThrTree head)
{//在中序线索二叉树上进行前序遍历BiThrTree p = head->lchild;while (p != head)//依序找打后继结点{printf("%c ", p->data);p = InPrePostNode(head, p);}
}
void ThpostInOrder(BiThrTree head)
{//在中序线索二叉树上进行后序遍历的逆序BiThrTree p = head->lchild;while (p != head)//依序找到前驱结点{printf("%c ", p->data);p = InPostPreNode(head, p);}
}

相关文章:

线索二叉树结构

线索二叉树结构1.线索二插树的作用2.线索二叉树的定义3.线索二叉树的结构4. 线索二叉树的操作4.1. 建立一棵中序线索二叉树4.2. 在中序线索二叉树上查找任意结点的中序前驱结点4.3. 在中序线索二叉树上查找任意结点的中序后继结点4.4. 在中序线索二叉树上查找任意结点在先序下的…...

6.网络爬虫——BeautifulSoup详讲与实战

网络爬虫——BeautifulSoup详讲与实战BeautifulSoup简介:BS4下载安装BS4解析对象Tag节点遍历节点find_all()与find()find_all()find()豆瓣电影实战前言: 📝​📝​此专栏文章是专门针对网络爬虫基础,欢迎免费订阅&#…...

Vue:路由管理模式

三种模式 Vue.js 的路由管理有三种模式: Hash 模式(默认):在 URL 中使用 # 符号来管理路由。例如,http://example.com/#/about。这个模式的好处是可以避免浏览器向服务器发送不必要的请求,并且不需要特殊…...

7个最好的PDF编辑器,帮你像编辑Word一样编辑PDF

PDF 是具有数字思维的组织的重要交流工具。提供高效的工作流程和更好的安全性,可以创建重要文档并与客户、同事和员工共享。文档的布局已锁定,因此无论在什么设备上查看,格式都保持不变。这是让每个人保持一致的好方法——尤其是那些使用Micr…...

【数据结构】树的介绍

文章目录前言树的概念及结构树的概念树的表示树在实际中的运用二叉树的概念及结构二叉树的概念现实中的二叉树特殊的二叉树二叉树的性质二叉树的储存结构顺序存储链式存储写在最后前言 🚩本章给大家介绍一下树。树的难度相对于前面的数据结构来说,又高了…...

CoreDNS 性能优化

CoreDNS 作为 Kubernetes 集群的域名解析组件,如果性能不够可能会影响业务,本文介绍几种 CoreDNS 的性能优化手段。合理控制 CoreDNS 副本数考虑以下几种方式:根据集群规模预估 coredns 需要的副本数,直接调整 coredns deployment 的副本数:k…...

前端三剑客常见面试题及其答案

目录 1、什么是 HTML? 2、什么是 CSS? 3、什么是 JavaScript? 4、什么是盒模型? 5、什么是浮动? 6、什么是定位? 7、什么是选择器? 8、什么是事件? 前端的三剑客指的是 HTML…...

【DFS专题】深度优先搜索 “暴搜”优质题单推荐 10道题(C++ | 洛谷 | acwing)

文章目录题单一、模板 [极为重要]全排列DFS组合型DFS指数DFS二、专题烤鸡 (指数BFS)P1088 火星人 【全排列】P1149 火彩棒 [预处理 ]P2036 PERKETP1135 奇怪的电梯 暴力P1036 [NOIP2002 普及组] 选数 (组合)P1596 [USACO10OCT]Lake Counting …...

微信小程序自定义组件生命周期有哪些?

微信小程序自定义组件的生命周期函数分为三类: 创建时执行的生命周期函数、更新时执行的生命周期函数和销毁时执行的生命周期函数。 下面是具体的生命周期函数及其触发时机: 创建时执行的生命周期函数: created:在组件实例刚刚…...

Linux就该这么学(六)

一、从“/”开始 Linux 系统中的文件和目录名称是严格区分大小写的。例如,root、rOOt、rooT 均代表不同的目录,并且文件名称中不得包含斜杠(/)。Linux 系统中的文件存储结构如下图所示。 在 Linux 系统中,最常见的目录…...

目标检测算法——YOLOv5/v7/v8改进结合涨点Trick之Wise-IoU(超越CIOU/SIOU)

超越CIOU/SIOU | Wise-IoU助力YOLO强势涨点!!! 论文题目:Wise-IoU: Bounding Box Regression Loss with Dynamic Focusing Mechanism 论文链接:https://arxiv.org/abs/2301.10051 ​ 近年来的研究大多假设训练数据中的…...

【蓝桥杯选拔赛真题39】python输出数字组合 青少年组蓝桥杯python 选拔赛STEMA比赛真题解析

目录 python输出数字组合 一、题目要求 1、编程实现 2、输入输出...

网络安全工程师做什么?

​ 网络安全很复杂。数字化转型、远程工作和不断变化的威胁形势需要不同的工具和不同的技能组合。 系统必须到位以保护端点、身份和无边界网络边界。负责处理这种复杂安全基础设施的工作角色是网络安全工程师。 简而言之,网络安全工程师是负责设计和实施组织安全系…...

总结:K8S运维常用命令

一、部署./kubectl apply -f biz-healing-pod.yaml 二、查看部署的资源1、podkubectl get pod -A:获取所有pod没有IP?用-o wide参数看详细信息:./kubectl get pod -n deepflow -o wide2、service查看hubble-manager命名空间下有哪些service/d…...

你是真的“C”——进行动态内存分配库函数的使用详解

你是真的“C”——申请动态空间库函数的使用详解😎前言🙌一、为什么需要动态内存分配?💞free 函数😘malloc 库函数😘calloc 库函数😘realloc 库函数😘总结撒花💞&#x1…...

Python|蓝桥杯进阶第五卷——数论

欢迎交流学习~~ 专栏: 蓝桥杯Python组刷题日寄 蓝桥杯进阶系列: 🏆 Python | 蓝桥杯进阶第一卷——字符串 🔎 Python | 蓝桥杯进阶第二卷——贪心 💝 Python | 蓝桥杯进阶第三卷——动态规划 ✈️ Python | 蓝桥杯进阶…...

用Python实现单例模式

什么是单例模式单例模式是指在内存中只会创建且仅创建一次对象的设计模式。在程序中多次使用同一个对象且作用相同时,为了防止频繁地创建对象使得内存飙升,单例模式可以让程序仅在内存中创建一个对象,让所有需要调用的地方都共享这一单例对象…...

交叉编译说明:工具链安装和环境变量配置

目录 一 简单了解交叉编译 ① 什么是交叉编译 ② 为什么需要交叉编译 ③ 宿主机和目标机 二 搭建交叉编译工作环境 ① 安装工具链 ② 配置环境变量 ● 配置临时环境变量 ● 配置永久环境变量 三 交叉编译宿主机和目标机 ● 宿主机编译生成的可执行文件下载到目…...

文件上传的多种利用方式

文件上传的多种利用方式 文件上传漏洞除了可以通过绕过检测进行webshell的上传之外,还有多种其它的漏洞可以进行测试。 XSS漏洞 文件名造成的XSS 当上传任何文件时,文件名肯定是会反显示在网页上,可以使用 XSS Payload做文件名尝试将其上传到…...

盘一盘C++的类型描述符(二)

先序文章请看 盘一盘C的类型描述符(一) 稍微组合一下的复杂类型 数组指针类型的数组类型 数组的指针类型我们已经了解了,那么,以这种类型作为元素的数组类型怎么搞? using type int (*)[3]; // 元素类型是数组指针…...

G-Helper完整指南:轻量级华硕笔记本控制工具终极教程

G-Helper完整指南:轻量级华硕笔记本控制工具终极教程 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivobook, Zenbook, Exp…...

oracle logminer

Oracle LogMiner 日志挖掘 【一、LogMiner 核心概念】LogMiner 是 Oracle 内置的日志分析工具,通过解析 redo log / 归档日志, 提取其中的 SQL 变更记录,用于:• 数据审计(谁改了什么、什么时候改的) • 数…...

如何快速上手Udeler:新手必看的完整Udemy课程下载指南

如何快速上手Udeler:新手必看的完整Udemy课程下载指南 【免费下载链接】udemy-downloader-gui A desktop application for downloading Udemy Courses 项目地址: https://gitcode.com/gh_mirrors/ud/udemy-downloader-gui 想要随时随地学习你购买的Udemy课程…...

C++ 程序内存分区

C 程序运行时,操作系统会给进程分配虚拟地址空间,在 32/64 位系统中,逻辑上划分为 代码区、全局静态区、常量区、栈区、堆区 5 个区域。下面从存储内容、管理方式、生命周期、权限、代码示例、常见坑逐一拆解。一、代码区(Text 段…...

Gemini 3.5十大应用场景:从代码生成到视频创作

一、软件开发场景 1.1 代码自动生成 Gemini 3.5 Flash在编码基准测试中达到76.2%,可以: 理解复杂技术文档生成高质量代码自动编写测试用例 # 代码生成示例 prompt """ 根据以下需求编写Python代码: 1. 创建一个REST API服…...

Cursor Free VIP:深入解析AI编程助手破解工具的技术实现与应用

Cursor Free VIP:深入解析AI编程助手破解工具的技术实现与应用 【免费下载链接】cursor-free-vip [Support 0.45](Multi Language 多语言)自动注册 Cursor Ai ,自动重置机器ID , 免费升级使用Pro 功能: Youve reached …...

MultiHighlight插件:让代码阅读不再痛苦的终极解决方案

MultiHighlight插件:让代码阅读不再痛苦的终极解决方案 【免费下载链接】MultiHighlight Jetbrains IDE plugin: highlight identifiers with custom colors 🎨💡 项目地址: https://gitcode.com/gh_mirrors/mu/MultiHighlight 你是否…...

如何快速安装elan:Lean版本管理器的完整指南

如何快速安装elan:Lean版本管理器的完整指南 【免费下载链接】elan The Lean version manager 项目地址: https://gitcode.com/gh_mirrors/el/elan elan是一个专门为Lean定理证明器设计的版本管理工具,它能让你轻松管理多个Lean安装版本。无论你是…...

在自动化脚本中集成Taotoken API并观察其长时间运行的可靠性

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 在自动化脚本中集成Taotoken API并观察其长时间运行的可靠性 对于需要长时间、周期性调用大模型API的自动化任务而言,服…...

3个12位ADC+17个定时器+摄像头接口:STM32F207IGT6的电机控制与机器视觉资源

STM32F207IGT6:176引脚工业级MCU的连接性与性能解析在工业自动化、电机控制以及物联网网关等应用中,MCU的性能不仅取决于主频,更取决于内部总线架构对瓶颈的突破。STM32F207IGT6是意法半导体STM32F2系列中的大容量型号,采用2424mm…...