首页 > 其他分享 >数据结构复习笔记5.3:线索二叉树

数据结构复习笔记5.3:线索二叉树

时间:2024-06-04 23:58:35浏览次数:17  
标签:结点 5.3 NULL 后继 BTNode 前驱 二叉树 数据结构 线索

1.前言

        在n个结点的⼆叉链表中,必定有n+1个空链域。⽽遍历运算是最重要的,也是最常⽤的运算⽅ 法,之前的⽆论是递归与非递归的算法实现遍历效率其实都不算⾼。

        现有⼀棵结点数⽬为n的⼆叉树,采⽤⼆叉链表的形式存储。对于每个结点均有指向左右孩⼦的 两个指针域,⽽结点为n的⼆叉树⼀共有n-1条有效分⽀路径。那么,则⼆叉链表中存在2n-(n-1)=n+1个 空指针域。那么,这些空指针造成了空间浪费。

        若将遍历后对应的有关前驱和后继预存起来 ,则从第一个结点开始就能很快“顺藤摸瓜 ”而遍历整个树。

例如如图:

        如图所示⼆叉树的中序遍历结果 为DBEAC,可以得知A的前驱结点为E,后继结点为C。但是,这种关系的获得是建⽴在完成遍历后得到的,那么可不可以在建⽴⼆叉树时就记录下前驱后继的关系呢,那么在后续寻找前驱结点和后继结点时将大大提升效率。

2.相关术语

线索: 指向结点前驱或后继的指针

线索链表: 以五域线索结点构成的二叉链表

线索二叉树: 加上线索的二叉树

线索化: 对二叉树以某种次序遍历使其变为线索二叉树的过程

3.规则

现将某结点的空指针域指向该结点的前驱后继,定义规则如下:

若结点的左⼦树为空,则该结点的左孩⼦指针指向其前驱结点。

若结点的右⼦树为空,则该结点的右孩⼦指针指向其后继结点。

这种指向前驱和后继的指针称为线索。将⼀棵普通⼆叉树以某种次序遍历,并添加线索的过程称为线索化。

可以将⼀棵⼆叉树线索化为⼀棵线索⼆叉树,那么新的问题产⽣了。我们如何区分⼀个结点的 lchild指针是指向左孩⼦还是前驱结点呢?

结点结构:

为了解决这⼀问题,现需要添加标志位ltag,rtag。

并定义规则如下:

ltag为0时,指向左孩⼦,为1时指向前驱

rtag为0时,指向右孩⼦,为1时指向后继

4.代码呈现

以中序遍历为例

1.结点结构
/*假设一个二叉树含有n个结点,采用链式存储,一共会有2n个指针域,有n+1的指针域为NULL,有n-1个指针有数值
会造成极大的空间浪费
以中序为例  如何快速的找到某个结点的前驱和后继

规则如下:如果一个结点的左孩子为空,左孩子指针指向其前驱
		  如果一个结点的右孩子为空,右孩子指针指向其后继

根据遍历序列不同,线索也分为三类:中序线索化,先序线索化,后序线索化

线索化:内存的优化
*/
//二叉链表的结点结构
typedef struct BTNode
{
	char data;
	struct BTNode* left;
	struct BTNode* right;
	int lflag, rflag;
}BTNode, *Btree;

BTNode * pre = NULL;

int flag; //0是插入左孩子 1是插入右孩子
2.初始化结点插入
Btree initTree(char x)
{
	BTNode *r = new BTNode;
	if (r == NULL)
	{
		cout << "defate!" << endl;
		return NULL;
	}
	else
	{
		r->data = x;
		r->left = r->right = NULL;
		r->rflag = r->lflag = 0;
		return r;
	}
}

BTNode *find(Btree r, char fx)
{
	if (r == NULL || r->data == fx)
	{
		return r;
	}
	if (r->left != NULL && r->lflag == 0)
	{
		BTNode * f = find(r->left, fx);
		if (f != NULL && f->data == fx)
		{
			return f;
		}
	}
	if (r->right != NULL && r->rflag == 0)
	{
		BTNode * f = find(r->right, fx);
		if (f != NULL && f->data == fx)
		{
			return f;
		}
	}
	return NULL;
}

void insert(BTNode * r, char x, char fx, int flag)
{
	BTNode * f = find(r, fx);//寻找父亲指针
	if (f != NULL)
	{
		BTNode *s = new BTNode;
		s->data = x;
		s->left = s->right = NULL;
		s->rflag = s->lflag = 0;
		if (flag == 0)
		{
			f->left = s;
		}
		else
		{
			f->right = s;
		}
	}
}
3.遍历后添加线索
void inOrder(Btree r)//遍历
{
	if (r == NULL && r->lflag == 0)
	{
		return;
	}
	if (r->left != NULL && r->rflag == 0)
	{
		inOrder(r->left);
	}
	//变成加线索
	visit(r);

	if (r->right != NULL)
	{
		inOrder(r->right);
	}
}

void visit(Btree r)
{
	//该函数的作用是(遍历后)添加线索,线索化结束后再具体找某个点的前驱和后继
	//x->lflag=1 前驱就是x->left
	//x->lflag=0 x->left是x的左孩子,x左子树中的最右边的结点才是x的前驱(为1则为前驱,为0则判断是不是后继)
	//x->rflag=1 后继就是x->right
	//x->rflag=0 x->right是x的右孩子,x右子树中的最左边的结点才是x的后继(为1则为后继,为0则判断是不是前驱)
	//原来visit可以想象成cout输出遍历完的树
	//现在将树想象成一条直线(pre是箭头),r为第一个遍历出来的元素
	//前驱可以通过r找,但是后继只能通过前一个即pre来找后继
	if (r->left == NULL)
	{
		r->left = pre;
		r->lflag = 1;//线索
	}
	if (pre != NULL && pre->right == NULL)
	{
		pre->right = r;//r是目前的r,pre是上一个r,没有下一个r
		pre->rflag = 1;//线索《===》r->rflag = 1
	}
	pre = r;//当访问完r时,r变成了上一个访问的结点(pre)
}

标签:结点,5.3,NULL,后继,BTNode,前驱,二叉树,数据结构,线索
From: https://blog.csdn.net/2301_81070376/article/details/139456410

相关文章

  • 二叉树遍历 和 线索二叉树
    文章目录1.1二叉树遍历1.1前提问题1:什么叫二叉树的遍历?二叉树的三种遍历:三个概念:遍历和访问和经过重要概念:遍历过程中的经过节点,不代表访问节点问题2:遍历和访问的联系?问题3:这个有顺序的编号的意义是什么?问题4:什么是访问?如何对节点进行访问?1.2二叉树遍历代码:二......
  • 【数据结构与算法 经典例题】链表的回文结构(图文详解)
                  ......
  • C语言数据结构实现-顺序表基本操作
    顺序表,全名顺序存储结构,是线性表的一种。通过《什么是线性表》一节的学习我们知道,线性表用于存储逻辑关系为“一对一”的数据,顺序表自然也不例外。不仅如此,顺序表对数据的物理存储结构也有要求。顺序表存储数据时,会提前申请一整块足够大小的物理空间,然后将数据依次存储起来,存储时......
  • 代码随想录算法训练营day14(二叉树)
    代码随想录算法训练营day14(二叉树):学习内容:今天学习二叉树。二叉树节点标准写法(当前节点值,左右子节点,有点像链表节点的定义):structTreeNode{intval;TreeNode*left;TreeNode*right;TreeNode(intx):val(x),left(NULL),right(NULL){}};二......
  • MySql索引的数据结构
    mysql索引是什么?想象一下,你手上有一本数学教材,但是目录被别人给撕掉了,现在要你翻到三三角函数的那一页,该怎么办?没有了目录,就只有两种方法,要么一页一页翻,要么随机翻。如果数据表没有目录的话,那要查询满足条件的记录行,就需要进行全表扫描,现在的互联网应用,数据量都非常大,百万千......
  • 数据结构学习笔记-简单选择排序
    简单选择排序的算法设计与分析问题描述:设计并分析简单选择排序【算法设计思想】迭代选择:算法通过循环遍历数组,进行size次迭代。最小值选择:在每次迭代(i)中,算法致力于找到未排序子数组(arr[i]到arr[size-1])内最小元素的索引。这个最小元素将被选出来进行交换。交......
  • 12- Redis 中的 链表 数据结构
    Redis的List对象的底层实现之一就是链表。C语言本身没有链表这个数据结构,所以Redis自己设计了一个链表数据结构。1.链表节点结构设计先来看看【链表节点】结构的样子:typedefstructlistNode{  //前置节点  structlistNode*prev;  //后置节点 ......
  • 数据结构:树
    树,是一种数据结构,就像这样:这就是一棵二叉树,也就是最多有两个分支的树,这些圆圈就是树的节点,下面讲一下节点间的关系:1、最上面的那个节点叫根节点2、每一个节点的上面的连着的节点称作这个节点的父节点,根节点没有父节点。3、每一个节点连着的下面的节点称作这个节点的子节点......
  • 数据结构与算法-图
    图是由顶点(vertex)和边(edge)组成的一种数据结构。顶点代表图中的节点,边代表节点之间的关系。图可以分为有向图(directedgraph)和无向图(undirectedgraph)。有向图中的边有一个方向,而无向图中的边没有方向。常见的图算法包括广度优先搜索(BFS)、深度优先搜索(DFS)、拓扑排序(topologica......
  • 数据结构·栈和队列
    栈栈(Stack):只允许在一端插入或删除的线性表栈顶:线性表允许进行插入或删除的那一端栈底:固定的,不允许进行插入和删除的另一端特点:是受限的线性表,拥有线性关系;后进先出LIFO顺序栈使用顺序存储,自底向上存储数据元素,指针指向栈顶元素的位置操作s.top=-1;......