当前位置:网站首页>中序线索二叉树
中序线索二叉树
2022-06-25 22:02:00 【乖乖怪123】
线索二叉树
线索二叉树的基本概念
二叉树的线索化是将二叉链表中的空指针改为指向前驱或后继的线索。而前驱或后继的信息只有在遍历时才能得到,因此线索化二叉树的实现就是遍历一次二叉树
以中序线索二叉树的建立为例:
- 附设指针pre指向刚刚访问过的结点,指针p指向正在访问的结点,即pre指向p的前驱。
- 在中序遍历的过程中,检查p的左指针是否为空,若为空就将它指向pre; 检查pre的右指针是否为空,若为空就将它指向p
中序线索二叉树的构造
InThread
通过中序遍历对二叉树线索化的递归算法(就是让结点的空指针指向其中序遍历的前驱或后继结点)
//通过中序遍历对二叉树线索化的递归算法(就是让结点的空指针指向其前驱或后继结点)
//中序线索二叉树的构造, 左根右
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);//递归,线索化右子树
}//if(p != NULL)
}
CreateInThread
通过中序遍历建立中序线索二叉树的主过程算法如下:
这个函数的作用就是建立中序线索二叉树,调用InThread函数,并处理遍历的最后一个结点。
CreateInThread和InThread的具体关系:前者可以看做统领大局的工头,后者是具体搬砖的小工
//通过中序遍历建立中序线索二叉树的主过程算法如下:
void CreateInThread(ThreadTree &T){
ThreadTree pre=NULL;
if(T){
//非空二叉树,线索化
InThread(T,pre);//线索化二叉树
pre->rchild==NULL;//处理遍历的最后一个结点
pre->rtag=1;//@@@
}
}
带头结点的线索二叉树
如果不想让中序遍历的第一个结点的lchild 和最后一个结点的rchild 为NULL, 则必须要加头结点,不能将之指向树根,因为如下图所示,根的前驱结点和后继结点已经指向了根,如果再把中序遍历的第一个结点的lchild 和最后一个结点的rchild指向根节点,则遍历的时候无法保证结果的正确性。
总而言之即:
若让中序遍历的第一个结点的lchild 和最后一个结点的rchild 不为NULL,则必须额外添加一个Head头结点,不能简单指向根节点
中序线索二叉树的遍历
中序线索二叉树的结点中隐含了线索二叉树的前驱和后继信息。在对其进行遍历时,只要先找到序列中的第一个结点,然后依次找到结点的后继,直至其后继为空.
Firstnode
求中序线索二叉树中,中序序列下的第一个结点
//求中序线索二叉树中,中序序列下的第一个结点
ThreadNode *Firstnode(ThreadNode *p){
//printf("Firstnode:");
while(p->ltag==0){
p=p->lchild;//最左下结点(不一定是叶节点)
}
return p;
}
Nextnode
求中序线索二叉树中,结点p在中序序列下的后继
//求中序线索二叉树中,结点p在中序序列下的后继
ThreadNode *Nextnode(ThreadNode *p){
if(p->rtag==0){
return Firstnode(p->rchild);
}
else{
return p->rchild;//rtag==1 直接返回后继线索
}
}
Inorder
可以写出不含头结点的中序线索二叉树的中序遍历算法
//利用上面的两个算法,
//可以写出不含头结点的中序线索二叉树的中序遍历算法
void Inorder(ThreadNode *T){
for(ThreadNode *p=Firstnode(T);p!=NULL;p=Nextnode(p)){
visit(p);
}
}
完整测试代码
完整测试代码c++
注意:
- 还是要先创建二叉树,然后再对二叉树进行中序遍历线索化
- 在创建二叉树的时候要对ltag rtag进行初始化为0,表示lchild,rchild指向的是左/右孩子(而非前驱/后继),且初始化不能在结构体的定义中初始化,因为定义结构体时,并未给其分配内存,所以初值是无法存储的。应该声明结构体变量后,手工赋值。下面代码中是在malloc后就初始化
- 因为线索化二叉树后各个结点之间都穿成一个环了,所以在中序递归遍历和后序递归销毁的函数中需要对ltag rtag进行判断。
//线索二叉树
#include<stdio.h>
#include<stdlib.h>
#define ElemType char
//tag为0表示指向左/右孩子,为1表示指向结点的前驱/后继
typedef struct ThreadNode{
ElemType data;//数据元素
struct ThreadNode *lchild,*rchild;//左右孩子指针
int ltag;//因为定义结构体时,并未给其分配内存,所以初值是无法存储的。应该声明结构体变量后,手工赋值
int rtag;//左右线索标记
}ThreadNode,*ThreadTree;
void visit(ThreadTree T){
printf("%c ",T->data);
}
//中序线索二叉树的构造, 左根右
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);//递归,线索化右子树
}//if(p != NULL)
}
//通过中序遍历建立中序线索二叉树的主过程算法如下:
void CreateInThread(ThreadTree &T){
//ThreadNode *Head = (ThreadNode*)malloc(sizeof(ThreadNode));
// Head->lchild=T;
//Head->ltag=1;
//ThreadTree pre=T;
ThreadTree pre=NULL;
if(T){
//非空二叉树,线索化
InThread(T,pre);//线索化二叉树
//Head->rchild=pre;
//Head->rtag=1;
pre->rchild==NULL;
//pre->rchild=T;//处理遍历的最后一个结点
pre->rtag=1;
}
}
//求中序线索二叉树中,中序序列下的第一个结点
ThreadNode *Firstnode(ThreadNode *p){
//printf("Firstnode:");
while(p->ltag==0){
p=p->lchild;//最左下结点(不一定是叶节点)
}
return p;
}
//求中序线索二叉树中,结点p在中序序列下的后继
ThreadNode *Nextnode(ThreadNode *p){
if(p->rtag==0){
return Firstnode(p->rchild);
}
else{
return p->rchild;//rtag==1 直接返回后继线索
}
}
//利用上面的两个算法,
//可以写出不含头结点的中序线索二叉树的中序遍历算法
void Inorder(ThreadNode *T){
for(ThreadNode *p=Firstnode(T);p!=NULL;p=Nextnode(p)){
visit(p);
}
}
//创建线索二叉树,按前序输入, #表示空节点
bool CreateThreadTree(ThreadTree &T){
ElemType ch;
scanf("%c", &ch);
if(ch == '#'){
//printf("您要创建一棵空树吗?\n");
T=NULL;
return false;
}
else{
T=(ThreadTree)malloc(sizeof(ThreadNode));
T->ltag=T->rtag=0;
if(!T){
printf("malloc failure\n");
return false;
}
T->data = ch;
CreateThreadTree(T->lchild);
CreateThreadTree(T->rchild);
return true;
}
}
bool DestroyThreadTree(ThreadTree T){
if(T==NULL){
printf("空节点\n");
return false;
}
if(T->ltag!=1)
DestroyThreadTree(T->lchild);
if(T->rtag!=1)
DestroyThreadTree(T->rchild);
printf("销毁%c\n",T->data);
free(T);//@@@'
T=NULL;
return true;
}
//中序遍历线索二叉树
void InOrder(ThreadTree T){
if(T){
if(T->ltag!=1)
InOrder(T->lchild);
visit(T);
if(T->rtag != 1)
InOrder(T->rchild);
}
}
int main(){
ThreadTree T=NULL;
printf("按前序输入二叉树中节点的值(输入#表示空节点)\n");
CreateThreadTree(T);//输入前序,建立二叉树
CreateInThread(T);//通过中序遍历建立中序线索二叉树
ThreadNode *p=Firstnode(T);//求中序遍历下的第一个结点
printf("\n中序遍历的第一个结点p: %c\n",p->data);
ThreadNode* r=Nextnode(p);//求中序遍历下p的后继
printf("p的后继r: %c\n",r->data);
printf("中序遍历线索二叉树(递归InOrder ≈ 正常BinaryTree遍历): \n");
InOrder(T);
printf("\n");
printf("\n中序遍历线索二叉树(非递归Inorder ≈ Firstnode+Nextnode): \n");
Inorder(T);
printf("\n用完要记得销毁哦!\n");
DestroyThreadTree(T);
return 0;
}
输入样例


测试结果

边栏推荐
- hiberate架构介绍及环境搭建(非常详细)
- golang Make a list of intervals with sequential numbers
- C. Yet Another Card Deck-Educational Codeforces Round 107 (Rated for Div. 2)
- How to download the software package of CDH version
- 【AXI】解读AXI协议乱序机制
- Anaconda一文入门笔记
- Kotlin空指针Bug
- 分享一个OSGeo4W64下载好的库,基于qgis3.10的
- Implementation of sequence table: static and dynamic
- RepOptimizer: 其实是RepVGG2
猜你喜欢

Pycharm student's qualification expires, prompting no suitable licenses associated with account solution

#23class介绍

ACM. HJ16 购物单 ●●

(serial port Lora module) centrida rf-al42uh private protocol test at instruction test communication process

毕业旅行 | 伦敦5日游行程推荐

Qt 中文和英文分别使用不同的字体

Summary of common JDBC exceptions and error solutions

UE4 学习记录一 创建角色,并控制其移动

经典图像分割网络:Unet 支持libtorch部署推理【附代码】

Fegin client entry test
随机推荐
Count the number of different palindrome subsequences in the string
Download the latest V80 version of Google Chrome
头歌 第3关:使用线程锁(Lock)实现线程同步
Ble Low Power Bluetooth networking process and Bluetooth role introduction
Analysis on resource leakage /goroutine leakage / memory leakage /cpu full in go
Qt 中文和英文分别使用不同的字体
Beacon realizes asset management and indoor positioning based on 5.2 ultra-low power Bluetooth module efr32 (bg22ax)
18亿像素火星全景超高清NASA放出,非常震撼
Classic image segmentation network: UNET supports libtorch deployment reasoning [with code]
CSDN原力值
Pointer strengthening and improvement
The simplest screen recording to GIF gadget in history, licecap, can be tried if the requirements are not high
jdbc常见异常及错误解决办法汇总
关于go协程超时退出控制条件与方式分析
第六章 习题(678)【微机原理】【习题】
期末复习【机器学习】
CSDN force value
leetcode_ 136_ A number that appears only once
OBS-Studio-27.2.4-Full-Installer-x64.exe 下载
毕业旅行 | 伦敦5日游行程推荐
