数据结构复习指导之线索二叉树

news2024/11/28 18:41:04

文章目录

二叉树

考纲内容

复习提示

1.线索二叉树

1.1线索二叉树的基本概念

1.2中序线索二叉树的构造

1.3中序线索二叉树的遍历

1.4先序线索二叉树和后序线索二叉树

知识回顾


二叉树

考纲内容

(一)树的基本概念
(二)二叉树
           二叉树的定义及其主要特征;二叉树的顺序存储结构和链式存储结构;
           二叉树的遍历;线索二叉树的基本概念和构造
(三)树、森林
           树的存储结构;森林与二叉树的转换;树和森林的遍历
(四)树与二叉树的应用
           哈夫曼(Huffman)树和哈夫曼编码;并查集及其应用

复习提示

本章内容多以选择题或综合题的形式考查,但统考也会出涉及树遍历相关的算法题。树和二叉树的性质、遍历操作、转换、存储结构和操作特性等,满二叉树、完全二叉树、线索二叉树、哈夫曼树的定义和性质,都是选择题必然会涉及的内容。

1.线索二叉树

1.1线索二叉树的基本概念

遍历二叉树是以一定的规则将二叉树中的结点排列成一个线性序列,从而得到几种遍历序列,使得该序列中的每个结点(第一个和最后一个除外)都有一个直接前驱和直接后继。

命题追踪——后序线索二叉树的定义

传统的二叉链表存储仅能体现一种父子关系,不能直接得到结点在遍历中的前驱或后继。前面提到,在含n个结点的二叉树中,有n+1个空指针。这是因为每个叶结点都有2个空指针,每个度为1的结点都有1个空指针,空指针总数为2n0+n1,又n0=n2+1,所以空指针总数为n0+n1+n2+1=n+1(n0、n1、n2分别表示度为0、1、2的结点个数

由此设想能否利用这些空指针来存放指向其前驱或后继的指针?这样就可以像遍历单链表那样方便地遍历二叉树。

引入线索二叉树正是为了加快查找结点前驱和后继的速度。
规定:若无左子树,令 lchild指向其前驱结点;若无右子树,令 rchild 指向其后继结点。

如图 5.17所示,还需增加两个标志域,以标识指针域指向左(右)孩子或前驱(后继)。

线索二叉树的存储结构描述如下:

typedef struct ThreadNode{
    ElemType data;                      //数据元素
    struct ThreadNode *lchild,*rchild;  //左、右孩子指针
    int ltag,rtag;                      //左、右线索标志
}ThreadNode,*ThreadTree;

以这种结点结构构成的二叉链表作为二叉树的存储结构,称为线索链表,其中指向结点前驱和后继的指针称为线索。加上线索的二叉树称为线索二叉树。

1.2中序线索二叉树的构造

二叉树的线索化是将二叉链表中的空指针改为指向前驱或后继的线索。而前驱或后继的信息只有在遍历时才能得到,因此线索化的实质就是遍历一次二叉树

命题追踪——中序线索二叉树中线索的指向

以中序线索二叉树的建立为例。附设指针 pre 指向刚刚访问过的结点,指针p指向正在访问的结点,即 pre 指向p的前驱。在中序遍历的过程中,检査p的左指针是否为空,若为空就将它指向 pre;检査 pre 的右指针是否为空,若为空就将它指向p,如图 5.18 所示。

通过中序遍历对二叉树线索化的递归算法如下:

void InThread(ThreadTree &p,ThreadTree &pre){
    if(p!=NULL){
        InThread(p->lchild,pre);        //递归,线索化左子树
        if(p->lchild==NULL){            //当前结点的左子树为空
            p->lchild=pre;              //建立当前结点的前驱线索
            p->ltag=1;
         }
         if(pre!=NULL&&pre->rchild==NULL){ //前驱结点非空且其右子树为空
            pre->rchild=p;                 //建立前驱结点的后继线索
            pre->rtag=1;
         }
            pre=p;                    //标记当前结点成为刚刚访问过的结点
            InThread(p->rchild,pre);  //递归,线索化右子树
    }
}

通过中序遍历建立中序线索二叉树的主过程算法如下:

void CreateInThread(ThreadTree T){
    ThreadTree pre=NULL;
    if(T!=NULL){            //非空二叉树,线索化
        InThread(T pre);    //线索化二叉树
        pre->rchild=NULL;   //处理遍历的最后一个结点
        pre->rtag=l;
    }
}

为了方便,可以在二叉树的线索链表上也添加一个头结点,令其lchild域的指针指向二叉树的根结点,其 rchild 域的指针指向中序遍历时访问的最后一个结点;

令二叉树中序序列中的第一个结点的 lchild域指针和最后一个结点的 rchild 域指针均指向头结点。

这好比为二叉树建立了一个双向线索链表,方便从前往后或从后往前对线索二叉树进行遍历,如图 5.19 所示。

1.3中序线索二叉树的遍历

中序线索二叉树的结点中隐含了线索二叉树的前驱和后继信息。在对其进行遍历时,只要先找到序列中的第一个结点,然后依次找结点的后继,直至其后继为空。

中序线索二叉树中找结点后继的规律是:若其右标志为“1”,则右链为线索,指示其后继,否则遍历右子树中第一个访问的结点(右子树中最左下的结点)为其后继。

不含头结点的线索二叉树的遍历算法如下。

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;      //若rtag==1则直接返回后继线索
}

请读者自行分析并完成求中序线索二叉树的最后一个结点和结点p前驱的运算

3) 利用上面两个算法,可写出不含头结点的中序线索二叉树的中序遍历的算法:

void Inorder(ThreadNode *T){
    for(ThreadNode *p=Firstnode(T); p!=NULL; p=Nextnode(p))
        visit(p);
}

1.4先序线索二叉树和后序线索二叉树

上面给出了建立中序线索二叉树的代码,建立先序线索二叉树和建立后序线索二叉树的代码类似,只需变动线索化改造的代码段与调用线索化左右子树递归函数的位置。

以图 5.20(a)的二叉树为例给出手动求先序线索二叉树的过程:

  1. 先序序列为 ABCDF,然后依次判断每个结点的左右链域,若为空,则将其改造为线索。
  2. 结点A,B均有左右孩子;结点C无左孩子,将左链域指向前驱 B,无右孩子,将右链域指向后继D;
  3. 结点D无左孩子,将左链域指向前驱 C,无右孩子,将右链域指向后继F;
  4. 结点F无左孩子,将左链域指向前驱 D,无右孩子,也无后继,所以置空;

得到的先序线索二叉树如图 5.20(b)所示。

后序线索二叉树的过程:

  1. 后序序列为 CDBEA,结点 C无左孩子,也无前驱,所以置空,无右孩子,将右链域指向后继 D;
  2. 结点 D无左孩子,将左链域指向前驱C,无右孩子,将右链域指向后继B;
  3. 结点F无左孩子,将左链域指向前驱 B,无右孩子,将右链域指向后继 A;

得到的后序线索二叉树如图 5.20(c)所示。

如何在先序线索二叉树中找结点的后继?

若有左孩子,则左孩子就是其后继;若无左孩子但有右孩子,则右孩子就是其后继;若为叶结点,则右链域直接指示了结点的后继。

命题追踪——后序线索二叉树中线索的指向

在后序线索二叉树中找结点的后继较为复杂,可分三种情况

①若结点x是二叉树的根,则其后继为空;

②若结点x是其双亲的右孩子,或是其双亲的左孩子且其双亲没有右子树,则其后继即为双亲;

③若结点x是其双亲的左孩子,且其双亲有右子树,则其后继为双亲的右子树上按后序遍历列出的第一个结点。

图5.20(c)中找结点B的后继无法通过链域找到,可见在后序线索二叉树上找后继时需知道结点双亲,即需采用带标志域的三叉链表作为存储结构

知识回顾

 

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

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

相关文章

酷柚易汛ERP源码部署/售后更新/搭建/上线维护

一款基于FastAdminThinkPHPLayui开发的ERP管理系统,帮助中小企业实现ERP管理规范化,此系统能为你解决五大方面的经营问题:1.采购管理 2.销售管理 3.仓库管理 4.资金管理 5.生产管理,适用于:服装鞋帽、化妆品、机械机电…

代码审计-PHP模型开发篇动态调试反序列化变量覆盖TP框架原生POP链

知识点 1、PHP审计-动态调试-变量覆盖 2、PHP审计-动态调试-原生反序列化 3、PHP审计-动态调试-框架反序列化PHP常见漏洞关键字 SQL注入: select insert update delete mysql_query mysqli等 文件上传: $_FILES,type"file"&…

人工智能驱动的设计工具的兴起:彻底改变创意产业

人工智能驱动的设计工具的兴起:彻底改变创意产业 概述 人工智能 (AI) 正在改变创意产业,设计也不例外。人工智能驱动的设计工具正在彻底改变设计师的工作方式,提供无与伦比的效率、创造力和创新水平。从生成图像和设计到自动化日常任务&…

深度学习基础之《TensorFlow框架(17)—卷积神经网络》

一、卷积神经网络介绍 1、背景 随着人工智能需求的提升,我们想要做复杂的图像识别,做自然语言处理,做语义分析翻译等等,多层神经网络的简单叠加显然力不从心 2、卷积神经网络与传统多层神经网络对比 (1)传…

Java基础编程(高级部分)

1. 类变量和类方法 1.1 什么是类变量 类变量也叫静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值同样任何一个该类的对象去修改它时,修改的也是同一个变量。 1.2 定义类变量 1.3 访问类变量 类名.类变量名 或者 对…

【C语言】模拟实现深入了解:字符串函数

🔥引言 本篇将模拟实现字符串函数,通过底层了解更多相关细节 🌈个人主页:是店小二呀 🌈C语言笔记专栏:C语言笔记 🌈C笔记专栏: C笔记 🌈喜欢的诗句:无人扶我青云志 我自…

flowable多对并发网关跳转的分析

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio 演示地址:RuoYi-Nbcio后台管理系统 http://218.75.87.38:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码: h…

塑胶ERP系统都有什么用处

在当今竞争激烈的塑胶市场中,企业如何高效地管理从原料采购到产品销售的整个生产链,直接关系到企业的生存与发展。ERP系统作为一种先进的管理信息系统,正逐渐成为塑胶企业不可或缺的工具。那么,一款优秀的ERP系统,究竟…

C语言自定义类型——枚举

枚举 枚举定义枚举 与 #define使用写一个简易计算器的程序。 枚举定义 格式: enum name(枚举什么类型) {//数据 ... };枚举,顾名思义一 一 列举。 在生活当中有很多可以列举的东西。 如: //电脑桌面上的软件 enum App {QQ ,WeChat,CCtalk,…

ESG榜单冲击数据集(2000-2022年)

参照《财经研究》中刘柏(2024)的做法,以2015年为中点,根据商道荣绿2015年6月公开的ESG榜单数据,构建ESG榜单冲击的DID数据,如果公司属于ESG榜单冲击的公司,且年份≥2015,则为1&#…

OBS插件--视频回放

视频回放 视频回放是一款源插件,它可以将指定源的视频缓存一段时间(时间可以设定),将缓存中的视频添加到当前场景中后,可以快速或慢速不限次数的回放。这个功能在类似体育比赛的直播中非常有用,可以捕获指…

Leetcode - 周赛396

目录 一,3136. 有效单词 二,3137. K 周期字符串需要的最少操作次数 三,3138. 同位字符串连接的最小长度 四,3139. 使数组中所有元素相等的最小开销 一,3136. 有效单词 本题就是一道阅读理解题: 字符串长…

Docker Compose常用命令与属性

大家好,今天给大家分享Docker Compose的常用命令,以及docker-compose文件的属性。Docker Compose 是一个用于定义和运行多容器 Docker 应用应用的重要工具。它通过一个配置文件(docker-compose.yml)来详细定义多个容器之间的关联、…

爬虫-无限debug场景 解决方式

解决无限debug 场景1 1. 鼠标右键 选择 continue to here(此处不停留)2. 鼠标右键 选择 edite breakpoint 设置 10 保证条件不成立 这行永远不执行3.方法置空 1. 方法调用加断点2. 控制台 setInterval function name() {}4. 替换文件 5. hoo…

如何使用phpMyAdmin删除数据库中的表?

本周有一个客户,购买Hostease的Linux虚拟主机,询问我们的在线客服,如何使用phpMyAdmin删除数据库中的表?我们为用户提供相关教程,用户很快解决了遇到的问题。在此,我们分享这个操作教程,希望可以…

LeetCode63:不同路径Ⅱ

题目描述 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。 现在考虑网格中有障碍物。那么从左上角…

飞凌嵌入式FET113i-S核心板在国产FTU中的适配性分析

智能电网建设的不断推进,使配电自动化成为了提升电网运行效率、保障供电质量的关键技术。在配电自动化系统中,馈线终端单元(FTU)作为连接电网与用户的重要节点,承担着实时监控、故障检测与隔离、远程控制等多项关键任务…

SpringMVC传递参数

1.RequestMapping RequestMapping本身可以处理,get或post,指定了get或post之后,就只能处理对应的请求。 RequestMapping(value{"haihiyo","goodMoring"},methodRequestMethod.POST)2.RestFul风格 RestFul是一种风格 比如:网站的访…

知识付费系统怎么搭建_轻松拥有知识付费平台

在信息爆炸的时代,知识的获取已不再局限于传统的课堂和书籍。随着科技的进步和互联网的普及,我们迎来了一个全新的知识获取方式——知识付费。今天,就让我们一起探讨如何搭建一个专属于您的知识付费系统,开启智慧的大门&#xff0…

VScode查看以十六进制查看文件的插件说明

找到插件并下载 打开指定的文件 选择打开方式即可 结果如下