数据结构---二叉树线索化&&双向链表

我们在创建二叉树时,每个结点都记录的左右孩子的地址,但却不知道前驱是谁,后继是谁。同时创建完会有很多空指针,为了方便记录下每个结点的前一个结点(前驱)和后一个结点(后继)是什么,便可以充分利用这些空指针域。

例如一个结点没有左孩子,即它的左孩子指针指向空,这时我们可以让它的左指针指向它的前驱,若这个结点也没有右孩子,则这个结点的右指针指向它的后继。

图示:(空心箭头实线指向前期,实心箭头虚线指向后继)

对于我们如何知道结点的左右指针是指向左右孩子还是前驱后继,我们可以用bool标志,如果有左(右)孩子就用Link为0标志,

如果没有左右孩子就用Thread为1标志说明左右指针指向前驱和后继。

和双向链表结构一样,我们需要在二叉树线索链表上添加一个头结点(不是第一个结点),并且令头结点的左指针指向根点,右指针指向中序序列中的最后一个结点。

同时将第一个结点的左指针和最后一个结点的右指针都指向头结点。

这样的结构我们可以从第一个结点往后继遍历,也可以从最后一个结点往前驱遍历。

图示:

代码详解:

#include<iostream>
using namespace std;
bool Link = false, Thread = true;
int flag = 0;
struct Tree
{
	char data;
	Tree *lchild, *rchlid;//左右孩子
	bool LTag, RTal;//标志左右孩子是否存在
};

Tree *first;//头结点
Tree *root;//根
Tree *pre;//始终是线索化时的前一个结点;
//------------------------------------------------------------
//创建二叉树
void CreateTree(Tree *T)
{
	char ch;
	cin >> ch;
	flag++;
	if (ch == '#')//代表空,没有数值
		T->data = '#';
	else
	{
		first->rchlid = T;//使得first的右孩子指向最后一个结点
		T->data = ch;
		//------------------------------------------------------创建左子树
		Tree *TL = new Tree();
		T->lchild = TL;
		CreateTree(T->lchild); 
		//------------------------------------------------------创建右子树
		Tree *TR = new Tree();
		T->rchlid = TR;
		CreateTree(T->rchlid);
	}
}
//---------------------------------------------------------------没有线索化前的遍历
/*void print(Tree *T)
{
if (T->date == NULL)
return;
else
{
print(T->lchild);
cout << T->date;
print(T->rchlid);
}
}
*/
//------------------------------------------------------------------
//二叉树线索化
void InTreeding(Tree *T)
{
	if (T->data != '#')
	{
		InTreeding(T->lchild);//递归左子树线索化
							  //没有左孩子
		//---------------------------------------------------------
		if (T->lchild->data == '#')
		{
			T->lchild = pre;//左孩子指向前驱
			T->LTag = Thread;//前驱线索
		}
		if (pre->rchlid->data == '#')//前驱没有右孩子
		{
			pre->RTal = Thread;//后继线索
			pre->rchlid = T;//右孩子指向后继
		}
		pre = T;//保持pre指向T的前驱
		//----------------------------------------------------------
		InTreeding(T->rchlid);//递归右孩子线索化
	}
}
//遍历
void InoderTree(Tree *T)
{
	Tree *p;
	p = T->lchild;//指向根结点
	//当空树或遍历结束时p==T
	while (p != T)
	{
		while (p->LTag == Link)//当p->LTag==Thread时到达第一个结点
			p = p->lchild;
		cout << p->data;
		while (p->RTal == Thread&&p->rchlid != T)//存在后继且后继不指向头结点
		{
			p = p->rchlid;
			cout << p->data;
		}
		p = p->rchlid;//指向它的右孩子
	}

}

int main()
{
	first = new Tree();
	root = new Tree();
	pre = first;//使得pre一开始指向头节结点,方便让第一个结点的左孩子指向头结点
	first->lchild = root;//头结点的右孩子指向根点
	CreateTree(root);
	InTreeding(root);
	first->rchlid->RTal = 1;
	first->rchlid->rchlid = first;//让最后结点的右孩子也指向头结点
	InoderTree(first);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_41676901/article/details/81748078