当前位置: 首页 > 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]; // 元素类型是数组指针…...

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

PHP和Node.js哪个更爽?

先说结论&#xff0c;rust完胜。 php&#xff1a;laravel&#xff0c;swoole&#xff0c;webman&#xff0c;最开始在苏宁的时候写了几年php&#xff0c;当时觉得php真的是世界上最好的语言&#xff0c;因为当初活在舒适圈里&#xff0c;不愿意跳出来&#xff0c;就好比当初活在…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

Java - Mysql数据类型对应

Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

【2025年】解决Burpsuite抓不到https包的问题

环境&#xff1a;windows11 burpsuite:2025.5 在抓取https网站时&#xff0c;burpsuite抓取不到https数据包&#xff0c;只显示&#xff1a; 解决该问题只需如下三个步骤&#xff1a; 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

服务器--宝塔命令

一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行&#xff01; sudo su - 1. CentOS 系统&#xff1a; yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...