IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 线索二叉树C++代码及线索化过程详解 -> 正文阅读

[数据结构与算法]线索二叉树C++代码及线索化过程详解

我在这里不仅写了线索二叉树的普通代码,在代码中我还加入了线索化过程的打印,更好的帮助理解!

线索二叉树的概念

传统的二叉树存在很多空指针,能否利用这些空指针来存放指向其前驱或后继的指针?这样就可以像遍历单链表那样方便地遍历二叉树。引入线索二叉树正是为了加快查找结点前驱和后继的速度。
若无左子树,令lchild指向其前驱结点;若无右子树,令rchild指向其后继结点。如图所示,还需增加两个标志域标识指针域是指向左(右)孩子还是指向前驱(后继)。 这就是线索二叉树
在这里插入图片描述

中序线索二叉树的构造

二叉树的线索化是将二叉链表中的空指针改为指向前驱或后继的线索。而前驱或后继的信息只有在遍历时才能得到,因此线索化的实质就是遍历一次二叉树
以中序线索二叉树的建立为例。附设指针 pre 指向刚刚访问过的结点,指针p 指向正在访问的结点,即pre指向p 的前驱。在中序遍历的过程中,检查p的左指针是否为空,若为空就将它指向pre;检查pre的右指针是否为空,若为空就将它指向p,如图所示。
在这里插入图片描述

中序线索二叉树的遍历

中序线索二叉树的结点中隐含了线索二叉树的前驱和后继信息。在对其进行遍历时,只要先找到序列中的第一个结点,然后依次找结点的后继,直至其后继为空。在中序线索二叉树中找结点后继的规律是:若其右标志为“1”,则右链为线索,指示其后继,否则遍历右子树中第一个访问的结点(右子树中最左下的结点)为其后继


过程详解版代码

程序运行部分结果
在这里插入图片描述
代码

#include<iostream>
#include<cstdio>
#include<stdlib.h>
using namespace std;

#define OK 1
#define ERROR 0
#define OVERFLOW -1

#define TElemType char
#define Status int

/*二叉树的二叉线索表示*/
typedef enum {Link, Thread} PointerTag;	//子树不为空时,Link==0 表示指针;子树为空时,Thread==1表示线索
typedef struct BiThrNode{
	TElemType data;
	struct BiThrNode *lchild, *rchild;	//左右孩子 
	PointerTag LTag, RTag;				//左右标志 
}BiThrNode, *BiThrTree; 

int cnt = 0;

/*按照先序序列建立一棵线索二叉树*/
Status CreatBiThrTree(BiThrTree &T){
	//按照先序序列输入二叉树中结点的值(一个字符),#表示空树
	char ch;
	cin >> ch;
	if(ch == '#') T = NULL;
	else{
		if(!(T = (BiThrNode*)malloc(sizeof(BiThrTree)))) exit(OVERFLOW);
		T->data = ch;				//生成根节点 
		T->LTag = Link;
		T->RTag = Link;
		CreatBiThrTree(T->lchild);	//构造左子树 
		CreatBiThrTree(T->rchild);	//构造右子树 
	}
	return OK; 
}//CreatBiThrTree

/*中序线索化*/
void Visualize(BiThrTree p, BiThrTree pre){
	//线索化的可视化输出
	cout << "p指向的结点:";
	if(p != NULL) cout << p->data << '\t';
	else cout << "NULL\t";
	cout <<  "pre指向的结点:";
	if(pre != NULL) cout << pre->data << endl;
	else cout << "NULL" << endl; 
}
Status InThread(BiThrTree &p, BiThrTree &pre){
	Visualize(p, pre);
	if(p != NULL){
		cout << "------------------------------------>线索化" << p->data << "的左子树" << endl; 
		InThread(p->lchild, pre);	//递归,线索化左子树
		cout << "------------------------------------>" << p->data << "的左子树线索化完成" << '\t';
		if(p->lchild == NULL){		//如果左子树为空,建立前驱线索
			cout << p->data << "的前驱节点指向pre指向的结点" << endl; 
			p->lchild = pre;
			p->LTag = Thread;		
		}
		if(pre != NULL && pre->rchild == NULL){
			cout << pre->data << "的后继结点指向" << p->data << endl;
			pre->rchild = p;		//如果此时的前驱结点的右子树为空,建立后继线索 
			pre->RTag = Thread;
		}
		cout << "pre指向p所指向的结点" << endl;
		pre = p;					//pre后移
		cout << "------------------------------------>线索化" << p->data << "的右子树" << endl; 
		InThread(p->rchild, pre);	//递归,线索化右子树 
		cout << "------------------------------------>" << p->data << "的右子树线索化完成" << endl;
		cout << ++cnt << "次线索化之后:"; 
		Visualize(p, pre);
		cout << endl << endl; 
	}//else if(p == NULL) return ERROR;//空树返回错误 
	return OK;
}//InThread
Status CreatInThread(BiThrTree &T){
	BiThrTree pre = NULL;	//因为第一个结点一开始无前驱
	if(T != NULL){
		InThread(T, pre);	//线索化二叉树
		pre->rchild = NULL;	//处理到了最后一个结点,pre指向最后一个结点,右孩子设为空表示最后一个结点 
		pre->RTag = Thread; //表示指针 
	}
	return OK;
}//CreatInThread

/*打印结点*/
void visit(BiThrNode *p){
	cout << p->data;
}

/*中序递归遍历*/
void InOrder(BiThrTree T){
	if(T != NULL){
		InOrder(T->lchild);
		visit(T);
		InOrder(T->rchild);
	}
}

/*中序线索二叉树的遍历*/
BiThrNode *FirstNode(BiThrNode *p){
	//求中序线索二叉树中中序序列下的第一个结点
	while(p->LTag != Thread) p = p->lchild;	//找到最左下方的结点(中序的第一个结点)
	return p; 
}
BiThrNode *NextNode(BiThrNode *p){
	//求中序线索二叉树中结点p在中序序列的后继结点
	if(p->RTag == Link) 
		return FirstNode(p->rchild);		//如果有右子树,继续递归向下找 
	else return p->rchild;					//RTag==1,直接返回线索 
}
void InThreadOrder(BiThrTree T){
	//不含头结点的中序线索二叉树的中序遍历算法 
	for(BiThrNode *p = FirstNode(T); p != NULL; p = NextNode(p))
		visit(p);
}

/*主函数*/
int main(){
	cout << "---------------这是一个线索二叉树程序!---------------" << endl;
	cout << "-------------首先按照先序序列建立一棵线索二叉树-------" << endl << endl;
	cout << "按照先序序列输入二叉树中结点的值(一个字符),#表示空树" << endl;	
	BiThrTree T;
	CreatBiThrTree(T);
	cout << "二叉树的递归中序遍历:"; 
	InOrder(T);
	
//	if(s == 1) 
	cout << endl << endl << "-------------下面进行中序线索化-------------" << endl;
	cout << "--------------打印线索化的过程--------------" << endl;
	
	
	if(CreatInThread(T) == 1) cout << "--------------已完成线索化--------------" << endl;
	cout << "中序线索二叉树的非递归遍历序列:";
	InThreadOrder(T);
	
	return 0;
}
//测试示例:abc##de#g##f###

纯享版代码

#include<iostream>
#include<cstdio>
#include<stdlib.h>
using namespace std;

#define OK 1
#define ERROR 0
#define OVERFLOW -1

#define TElemType char
#define Status int

/*二叉树的二叉线索表示*/
typedef enum {Link, Thread} PointerTag;	//子树不为空时,Link==0 表示指针;子树为空时,Thread==1表示线索
typedef struct BiThrNode{
	TElemType data;
	struct BiThrNode *lchild, *rchild;	//左右孩子 
	PointerTag LTag, RTag;				//左右标志 
}BiThrNode, *BiThrTree; 

/*按照先序序列建立一棵线索二叉树*/
Status CreatBiThrTree(BiThrTree &T){
	//按照先序序列输入二叉树中结点的值(一个字符),#表示空树
	char ch;
	cin >> ch;
	if(ch == '#') T = NULL;
	else{
		if(!(T = (BiThrNode*)malloc(sizeof(BiThrTree)))) exit(OVERFLOW);
		T->data = ch;				//生成根节点 
		T->LTag = Link;				//这里一定要加上,不然后边会出错 
		T->RTag = Link;
		CreatBiThrTree(T->lchild);	//构造左子树 
		CreatBiThrTree(T->rchild);	//构造右子树 
	}
	return OK; 
}//CreatBiThrTree

/*中序线索化*/
Status InThread(BiThrTree &p, BiThrTree &pre){
	if(p != NULL){
		InThread(p->lchild, pre);	//递归,线索化左子树
		if(p->lchild == NULL){		//如果左子树为空,建立前驱线索
			p->lchild = pre;
			p->LTag = Thread;		
		}
		if(pre != NULL && pre->rchild == NULL){
			pre->rchild = p;		//如果此时的前驱结点的右子树为空,建立后继线索 
			pre->RTag = Thread;
		}
		pre = p;					//pre后移
		InThread(p->rchild, pre);	//递归,线索化右子树 
	}//else if(p == NULL) return ERROR;//空树返回错误 
	return OK;
}//InThread
Status CreatInThread(BiThrTree &T){
	BiThrTree pre = NULL;	//因为第一个结点一开始无前驱
	if(T != NULL){
		InThread(T, pre);	//线索化二叉树
		pre->rchild = NULL;	//处理到了最后一个结点,pre指向最后一个结点,右孩子设为空表示最后一个结点 
		pre->RTag = Thread; 		//表示指针 
	}
	return OK;
}//CreatInThread

/*打印结点*/
void visit(BiThrNode *p){
	cout << p->data;
}

/*中序递归遍历*/
void InOrder(BiThrTree T){
	if(T != NULL){
		InOrder(T->lchild);
		visit(T);
		InOrder(T->rchild);
	}
}

/*中序线索二叉树的遍历*/
BiThrNode *FirstNode(BiThrNode *p){
	//求中序线索二叉树中中序序列下的第一个结点
	while(p->LTag != Thread) p = p->lchild;	//找到最左下方的结点(中序的第一个结点)
	return p; 
}
BiThrNode *NextNode(BiThrNode *p){
	//求中序线索二叉树中结点p在中序序列的后继结点
	if(p->RTag == Link) 
		return FirstNode(p->rchild);				//如果有右子树,继续递归向下找 
	else return p->rchild;					//RTag==1,直接返回线索 
}
void InThreadOrder(BiThrTree T){
	//不含头结点的中序线索二叉树的中序遍历算法 
	for(BiThrNode *p = FirstNode(T); p != NULL; p = NextNode(p))
		visit(p);
}

/*主函数*/
int main(){
	BiThrTree T;
	CreatBiThrTree(T);
//	InOrder(T);	
	CreatInThread(T);
	cout << "遍历序列:"; 
	InThreadOrder(T);	
	return 0;
}
//abc##de#g##f###
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-06-01 15:26:10  更:2022-06-01 15:27:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 9:44:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码