文章目录

  • 一、定义
  • 二、结构
  • 三、常用操作
  • 结语
  • 附录

一、定义

前面学习了二叉树,在操作过程中发现了几个问题:

问题一:二叉树如何才能实现从一个指定结点开始遍历呢?
        问题二:在二叉树中如何找到指定结点p在遍历序列中的前驱和后继呢?

通过对以上问题的思考发现在二叉树中想要实现以上的功能都离不开从根结点到指定结点的搜索过程,可见在二叉树中实现以上操作是非常不方便的,为了解决这些问题就引出了线索二叉树这个概念。

所谓的线索二叉树就是加上线索的二叉树,我们知道在有n个结点的二叉树中必定存在n+1个空链域(叶子结点的左右孩子指针都为空),由此利用这些空链域来存放结点的前驱和后继的信息,构成线索。

由于进行"线索化"所选择的遍历序列不同,又可将线索二叉树分为中序线索二叉树、先序线索二叉树和后序线索二叉树,本文将较为详细的介绍中序线索二叉树的创建过程。

二、结构

线索化结点结构

若结点有左子树,则其IeftChild域指示其左孩子,否则令leftChild域指示其前驱;若结点有右子树,则其rightChild域指示其右孩子,否则令rightChild域指示其后继。为了避免混淆,尚需改变结点结构,增加两个标志域ltag和rtag。



中序线索二叉树示例

以中序遍历序列CBEDFAGH构成的线索二叉树

代码结构描述

#define ElemType char //元素类型
//标记指针域
typedef enum{LINK,THREAD}Tag_Type;
//线索化结点
typedef struct BinTreeNode
{ElemType data; //数据域struct BinTreeNode *leftChild; //左指针域struct BinTreeNode *rightChild; //右指针域/*左标记LINK:leftChild域指示结点的左孩子  THREAD:leftChild域指示结点的前驱*/Tag_Type ltag;/*左标记LINK:rightChild域指示结点的右孩子  THREAD:rightChild域指示结点的后继*/Tag_Type rtag; //右标记
}BinTreeNode;//二叉树类型
typedef struct BinTree
{BinTreeNode *root; //指向二叉树根结点ElemType     refvalue; //stop value
}BinTree;

三、常用操作

以下介绍中序线索二叉树的常用操作

初始化

//初始化二叉树
void InitBinTree(BinTree *bt, ElemType ref)
{bt->root = NULL;bt->refvalue = ref; //标明结束标记,如#
}

结点申请

BinTreeNode* _Buynode(ElemType x)
{//申请空间BinTreeNode *s = (BinTreeNode*)malloc(sizeof(BinTreeNode));assert(s != NULL);s->data = x;//传值s->leftChild = s->rightChild = NULL;s->ltag = s->rtag = LINK;//线索化之前左右标记都初始为指针链return s;
}

创建二叉树

//创建二叉树
void CreateBinTree(BinTree *bt, char *str)
{CreateBinTree(bt,bt->root,str);
}
void CreateBinTree(BinTree *bt, BinTreeNode *&t, char *&str)
{if(*str == bt->refvalue)t = NULL;else{t = _Buynode(*str);//获取一个二叉树结点//创建左子树CreateBinTree(bt,t->leftChild,++str);//创建右子树CreateBinTree(bt,t->rightChild,++str);}
}

对二叉树进行中序线索化

//创建中序线索化
void CreateInThread(BinTree *bt)
{BinTreeNode *pre = NULL;//第一个线索结点的前驱为空CreateInThread(bt->root,pre);pre->rightChild = NULL;//最后一个线索结点的后继为空pre->rtag = THREAD;//将右指针类型设置为后继类型
}
void CreateInThread(BinTreeNode *&t, BinTreeNode *&pre)
{if(t == NULL)return;//对左树进行线索化CreateInThread(t->leftChild,pre);if(t->leftChild == NULL)//判断是否到达左树最左端(叶子结点){//是  结点前序化/*注:起始时叶子结点的左右指针都为空,所以我们就利用叶子结点的左右指针域来建立线索*/t->ltag = THREAD;   //改变指针域指向类型,改为指向前驱结点t->leftChild = pre; //将左指针域指向其前驱结点}if(pre!=NULL && pre->rightChild==NULL){//前驱结点的后序化------>pre->rtag = THREAD; //将右指针域类型改成后继指针pre->rightChild = t; //将前驱结点的右指针指向后继}//左子树线索化创建完成,pre移动到此时子树的根结点pre = t;//对右子树进行线索化CreateInThread(t->rightChild,pre);
}

获取中序线索二叉树第一个访问的结点

//获取中序线索树的第一个要访问的结点
BinTreeNode* First(BinTree *bt)
{//传入根结点return First(bt->root);
}
BinTreeNode* First(BinTreeNode *t)
{if(t == NULL)return NULL;BinTreeNode *p = t;while(p->ltag == LINK) //移动到第一个结点处p = p->leftChild;return p; //返回
}

获取中序线索二叉树最后一个访问的结点

//获取中序线索树的最后一个要访问的结点
BinTreeNode* Last(BinTree *bt)
{return Last(bt->root);
}
BinTreeNode* Last(BinTreeNode *t)
{if(t == NULL)return NULL;BinTreeNode *p = t;while(p->rtag == LINK) //移动到最后一个结点处p = p->rightChild;return p; //返回
}

获取某结点的后继

//获取某结点的后继结点
BinTreeNode* Next(BinTree *bt, BinTreeNode *cur)
{return Next(bt->root,cur);
}
BinTreeNode* Next(BinTreeNode *t, BinTreeNode *cur)
{if(t==NULL || cur==NULL)return NULL;if(cur->rtag == THREAD) //判断当前结点的有标记是否指向后继return cur->rightChild;//是 返回return First(cur->rightChild);//否 获取右子树的第一个要访问的结点
}

获取某结点的前驱

//获取某结点的前驱
BinTreeNode* Prio(BinTree *bt, BinTreeNode *cur)
{return Prio(bt->root,cur);
}
BinTreeNode* Prio(BinTreeNode *t, BinTreeNode *cur)
{if(t==NULL || cur==NULL)return NULL;if(cur->ltag == THREAD)//判断当前结点的有标记是否指向前驱return cur->leftChild;//是 返回return Last(cur->leftChild);//否 获取左子树最后一个访问的结点
}

中序线索二叉树的中序遍历

//线索二叉树的中序遍历
void InOrder(BinTree *bt)
{InOrder(bt->root);
}
void InOrder(BinTreeNode *t)
{BinTreeNode *p;//按照访问顺序依次获取结点输出for(p=First(t); p!=NULL; p=Next(t,p)){printf("%c ",p->data);}printf("\n");
}

查找某个结点

//查找某一个结点
BinTreeNode* Search(BinTree *bt, ElemType key)
{return Search(bt->root,key);
}
BinTreeNode* Search(BinTreeNode *t, ElemType key)
{if(t == NULL)return NULL;if(t->data == key)return t;//按照中序遍历的形式进行线索二叉树的结点查找BinTreeNode *p;for(p=First(t); p!=NULL; p=Next(t,p)){if(p->data == key)return p;}return NULL;}

获取某结点的父结点

//获取某结点的父结点
BinTreeNode* Parent(BinTree *bt, BinTreeNode *cur)
{return Parent(bt->root,cur);
}BinTreeNode* Parent(BinTreeNode *t, BinTreeNode *cur)
{if(t==NULL || cur==NULL)return NULL;if(t == cur)return NULL;BinTreeNode *p;if(cur->ltag == THREAD) //判断当前结点的左指针是否指向前驱{//是p = cur->leftChild; //获取前驱结点if(p->rightChild == cur) //判断前驱结点的右孩子是否就是当前结点return p;}if(cur->rtag == THREAD) //判断右标记是否为后继结点{p = cur->rightChild; //获取后继结点if(p->leftChild == cur)//判断后继结点的左孩子是否为当前结点return p;}//如果不是以上的情况,那么就获取左子树中的第一个前驱结点p = First(cur->leftChild);p = p->leftChild;if(p!=NULL && p->rightChild == cur) //判断这个前驱结点的右孩子是否为当前结点return p;//如果顺着前驱结点没找到,那么就获取右子树的最后一个后继结点,利用后继结点查找父结点p = Last(cur->rightChild);return p->rightChild;
}

结语

对线索二叉树的介绍就到这里啦,希望这篇文章能给予你一些帮助,感谢各位人才的:点赞、收藏和评论,我们下次见。

附录

测试代码:线索二叉树详解(C语言版)

线索二叉树详解(C语言版)相关推荐

  1. 线索二叉树详解 - C语言

    目录 一.线索二叉树的定义 1.1 线索的概念 1.2 数据结构 1.3 优缺点 二.线索二叉树的构建 2.1 线索化 2.2 实现中序遍历线索化 三.线索二叉树的应用 3.1 求某个结点的中序后继 ...

  2. 数据结构殷人昆电子版百度云资源_数据结构精讲与习题详解(C语言版第2版清华大学计算机系列教材)...

    导语 内容提要 殷人昆编著的<数据结构精讲与习题详解(C语言版第2版清华大学计算机系列教材)>是清华大学出版社出版的<数据结构(C语言版)>(第2版)的配套教材,对" ...

  3. 【线索二叉树详解】数据结构06(java实现)

    线索二叉树 1. 线索二叉树简介 定义: 在二叉树的结点上加上线索的二叉树称为线索二叉树. 二叉树的线索化: 对二叉树以某种遍历方式(如先序.中序.后序或层次等)进行遍历,使其变为线索二叉树的过程称为 ...

  4. 【八大排序详解~C语言版】直接插入排序-希尔排序- 直接选择排序-堆排序-冒泡排序-快速排序-归并排序-计数排序

    八大排序 1.直接插入排序 2.希尔排序 3.直接选择排序 直接选择排序改进 4.堆排序 1.建堆 2.利用堆删除思想来进行排序 5.冒泡排序 6.快速排序 递归实现 非递归实现 7.归并排序 递归实 ...

  5. 你是真的“C”——详解C语言实现文件版通讯录

    详解C语言实现文件版通讯录

  6. #转载:杨辉三角形实现过程详解-c语言基础

    杨辉三角形实现过程详解-C语言基础 十一一个人 2018-12-26 06:45:45 6465 收藏 28 最后发布:2018-12-26 06:45:45首发:2018-12-26 06:45:4 ...

  7. (十二)命令模式详解(故事版)- 转

    作者:zuoxiaolong8810(左潇龙),转载请注明出处. 背景:小左是魔都某公司技术部的一名屌丝程序猿,每天的工作就是维护一个20世纪的古董级项目,由于公司不大,所以公司很多制度不太完善,导致 ...

  8. 《Linux设备驱动开发详解(第2版)》隆重出版

    Linux设备驱动开发详解(第2版)(前一版狂销3万册,畅销书最新升级) [新品] 点击看大图     基本信息 * 作者: 宋宝华       * 出版社:人民邮电出版社     * ISBN:97 ...

  9. 教程直播第8期|一文详解 OceanBase 社区版生态工具 ODP OCP

    在 OceanBase 生态大家庭中,除了 OceanBase 数据库内核部分,还有很多功能强大的周边工具,这些工具实现了不同的功能,满足了客户多样化的需求.本文将介绍两个极具代表性的的生态工具,帮助 ...

最新文章

  1. HashMap 散列初体验
  2. mysql bin.000047_mysql-bin.0000X 日志文件处理
  3. vscode如何查看修改过的部分_编辑器 VS Code 如何快速查看 Go 接口?
  4. 【Linux复习——温故知新
  5. 单例模式中的多线程分析synchronized
  6. gitlab 数据同步
  7. 六自由度机器人(机械臂)运动学建模及运动规划系列(一)——简介
  8. SPI 接口驱动电路设计
  9. 文件删不掉需要管理员权限?分享解决方法
  10. 微信公众号和服务器的关系,微信公众号订阅号和服务号主要区别
  11. AIX 5300-06-01 + Oracle 9.2.0.6 = ORA-27061
  12. 思考力——提升企业竞争力的核心因素
  13. 【九校3D2T3】世界第一的猛汉王
  14. stata两种方法制作限制立方条图
  15. 移动硬盘盒芯片(SATAIII)
  16. idea下载数据库驱动太慢?
  17. FFmpeg学习之八(FFmpeg源码编译)
  18. 隐私泄露无孔不入?扫地机器人已成新型“窃听器”
  19. 20.JavaScript6
  20. Ranger (一) --------- Ranger 概述

热门文章

  1. 【Python天气预报系统】又要降温,这个冬天你准备好棉衣秋裤了吗?看了不后悔系列之Python打造智能天气预报系统,爆赞。
  2. Java:如何获取当前时间
  3. 达芬奇密码 第二章(1)
  4. 域名解析服务(DNS)之bind
  5. 设计模式学习笔记(十五)-桥接模式
  6. mongodb 无法查出数据_mongodb查询不到数据
  7. 归并排序算法原理及实现
  8. 教你整理归类文件保存在指定位置
  9. 5个免费的城市规划软件
  10. 58转转技术总监骆俊武:监控系统选型?必读本篇!