数据结构——线索二叉树

本文详细介绍了线索二叉树的概念,包括前序、中序和后序线索二叉树的构造方法。线索二叉树通过增加线索指针,使得在二叉树中查找前驱和后继节点变得更加高效。文章提供了C++实现的代码示例,展示了如何进行线索化的具体步骤以及查找前驱和后继节点的算法。线索二叉树在二叉树遍历和节点查找等方面有重要应用。
摘要由CSDN通过智能技术生成

1.介绍

在二叉树中,查找某种遍历(如前中后序遍历、层次遍历)的前驱后继,有两种方法可以解决。

1.每次取前驱或者后继时,遍历整棵树,显然这是时间复杂度较大且不可取的。

2.将结点结构变为如下结构。

若结点有左子树,left指向左孩子否则指向某种遍历的前驱。

若结点有右子树,right指向右孩子,否则指向某种遍历的后继。

我们假设遍历的第一个结点前驱和最后一个结点前驱为NULL。

因为有三种遍历,前中后序遍历对应着三种线索二叉树。

分别为前序、中序、后序线索二叉树。中序线索二叉树结构如下:

假设一个普通的二叉树有n个结点,则有2n个指针。因为这n个结点只有根节点没有被指,因此有n+1个指针没有被用上。在线索二叉树这些指针就可以完全被利用。

2.线索化

将一个普通的二叉树构成线索二叉树的过程叫作线索化

建立一个线索二叉树,我们可以用两个指针pre指向前驱结点和指针current指向当前结点来完成。

我们按照遍历方式对每个结点进行判定,判定其左右指针是否为空,为空就可以连接它的前驱和后继。

(1)中序线索二叉树的做法

做法如下:

template<class T>
void threadTree<T>::inThread()
{
	if (root)//当前根节点不为空
	{
		node* pre = nullptr;
		inThreadNode(pre, root);//进行线索化
		pre->right = nullptr;//完成线索化最后一步
		pre->rTag = true;
	}
}
template<class T>
void threadTree<T>::inThreadNode(node* &pre,node* current)
{
	if (!current)//当前指针为空就返回
		return;
	inThreadNode(pre, current->left);
    //连接前驱
	if (!current->left)//当前左指针为空
	{
		current->left = pre;
		current->lTag = true;
	}
    //连接后继
	if (pre && !pre->right)//pre指针存在且没有右孩子
	{
		pre->right = current;
		pre->rTag = true;
	}
	pre = current;
	inThreadNode(pre, current->right);
}

其实不必把上面的函数看的多复杂,把这两个if看成一个函数,如果把这个函数换成输出当前结点,这个函数就变成了中序遍历函数。

(2)先序线索二叉树的做法

线索化的过程和中序的区别只在于遍历顺序的问题,将其改成前序遍历就好。

另外一个需要注意的是转圈圈问题:

template<class T>
void threadTree<T>::inThreadNode(node* &pre,node* current)
{
	if (!current)//当前指针为空就返回
		return;
    //连接前驱
	if (!current->left)//当前左指针为空
	{
		current->left = pre;
		current->lTag = true;
	}
    //连接后继
	if (pre && !pre->right)//pre指针存在且没有右孩子
	{
		pre->right = current;
		pre->rTag = true;
	}
    pre = current;
    if(!current->lTag)//不同的地方
	    inThreadNode(pre, current->left);
	inThreadNode(pre, current->right);
}

我们知道当先序遍历时,我们如果对一最左下个结点进行上面的函数时,它原本空的左指针已经指向了前驱,如果不加条件,就会一直转圈不出来。

(3)后序线索二叉树的做法

改为后续遍历,除了顺序不一样外,几乎和中序线索化函数相同。

template<class T>
void threadTree<T>::inThreadNode(node* &pre,node* current)
{
	if (!current)//当前指针为空就返回
		return;
	inThreadNode(pre, current->left);
    //连接前驱
	if (!current->left)//当前左指针为空
	{
		current->left = pre;
		current->lTag = true;
	}
    //连接后继
	if (pre && !pre->right)//pre指针存在且没有右孩子
	{
		pre->right = current;
		pre->rTag = true;
	}
	pre = current;
	inThreadNode(pre, current->right);
}

3.查前驱后继 

(1)中序前驱后继

考虑一个结点的前驱,两种情况。

1.left指向的不是左孩子,则其left是前驱,直接返回。

2.如果是左孩子,则其前驱是其左孩子的最右下孩子的结点

考虑一个结点的后继,两种情况。

1.right指向的不是右孩子,则其right指向的是后继,直接返回。

2.如果是右孩子,则其前驱是其右孩子的最左下孩子的结点

总的:

 

#pragma once
#include<iostream>
template<class T>
class threadTree
{
public:
	struct node
	{
		T data;
		node* left;
		node* right;
		bool lTag;
		bool rTag;
		node(const T& d=0, node* l = nullptr, node* r = nullptr, bool lT = false, bool rT = false)
			:data(d),left(l),right(r),lTag(lT),rTag(rT){}
	};
	node* root;
	threadTree() :root(nullptr) {}
	~threadTree() { clear(root); }
	void inThread();//将二叉树中序线索化
	node* last(node* current);//求前驱
	node* next(node* current);//求后继
	void inOrder(node* p);//遍历
private:
	void clear(node* root);//删除root树的所有结点
	void inThreadNode(node*& pre, node* current);//判断是否可以连接前驱后继,如果可以则连接
};
template<class T>
void threadTree<T>::clear(node* root)
{
	node* pre = root;
	node* p = next(pre);
	while(p)
	{
		delete pre;
		pre = p;
		p = next(pre);
	}
}
template<class T>
void threadTree<T>::inThread()
{
	if (root)
	{
		node* pre = nullptr;
		inThreadNode(pre, root);
		pre->right = nullptr;
		pre->rTag = true;
	}
}
template<class T>
void threadTree<T>::inThreadNode(node* &pre,node* current)
{
	if (!current)
		return;
	inThreadNode(pre, current->left);
	if (!current->left)
	{
		current->left = pre;
		current->lTag = true;
	}
	if (pre && !pre->right)
	{
		pre->right = current;
		pre->rTag = true;
	}
	pre = current;
	inThreadNode(pre, current->right);
}
template<class T>
typename threadTree<T>::node* threadTree<T>::last(node* current)
{
	//前驱两种情况,一种left指针所指对象就是前驱,一种就是左子树的最右下结点
	node* p = current->left;
	if (!current->lTag)
	{
		while (!p->rTag)
			p = p->right;
	}
	return p;
}
template<class T>
typename threadTree<T>::node* threadTree<T>::next(node* current)
{
	node* p = current->right;
	if (!current->rTag)
	{
		while (!p ->lTag)
			p = p->left;
	}
	return p;
}
template<class T>
void threadTree<T>::inOrder(node* p)
{
	if (!p)
		return;
	if (p->left)
		inOrder(p->left);
	std::cout << p->data << " ";
	if (p->right)
		inOrder(p->right);
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值