数据结构(C++)——二叉树的前,中,后线索化

本文详细介绍了二叉树的线索化过程,包括如何利用二叉树中的空指针域来存储节点的前驱和后继信息,以及如何通过中序、前序和后序遍历来实现线索化。此外,还提供了具体的C++实现代码和测试案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        从二叉树的遍历我们可以得知:遍历二叉树是以一定规则将二叉树中结点排成一个线性序列,得到二叉树中的结点的前序序列或中序序列或后序序列。其实质上市对一个非线

性结构进行线性化操作,使得每个结点(除去第一个和最后一个)在这些线性序列中有接近有一个直接的前驱后继。

        但是,我们之前写的二叉树结构只能找到节点的做孩子和右孩子的信息,而不能直接得到结点在任一序列中的前驱和后继信息,而这种信息只有在遍历动态中得到。

        那么,如何来保存这种在遍历过程中得到的信息呢?

        由于在有n个结点的二叉树中必定有n+1个空链域。那么我们就利用这些空链域来存放结点的前驱和后继的信息。

        规则如下:

        1、首先增加两个标志域:

               typedef enum{LINK,TREAD}Tag;

        2、若结点有左子树,则其left域指向其左孩子,否则令left指向其后继。并修改标志域修改为TREAD。

               若结点有右子树,则其right域指向其左孩子,否则令right指向其后继。并修改标志域修改为TREAD。 

#ifndef _TREADBINTREE_H
#define _TREADBINTREE_H
#include"AllHead.h"
template<class T>
class TreadBinTree;
typedef enum{LINK,TREAD}Tag;
template<class T>
class BinTreeNode
{
	friend class TreadBinTree<T>;
private:
	BinTreeNode<T> *left;
	BinTreeNode<T> *right;
	T data;
	Tag ltag;
	Tag rtag;//加入两个标志
public:
	BinTreeNode()
	{
		left = NULL;
		right = NULL;
		ltag = LINK;
		rtag = LINK;
	}
	BinTreeNode(T d):data(d)
	{
		left = NULL;
		right = NULL;
		ltag = LINK;
		rtag = LINK;
	}
	T getData(){return data;}
};
template<class T>
class TreadBinTree
{
public:
	BinTreeNode<T> *root;
	char flag;
public:
	TreadBinTree()
	{
		root = NULL;
		flag = '#';
	}
public:
	void create_Bintree()//-------------------------------------创建一棵二叉树
	{
		create_Bintree(root);
	}
	void create_inTreadBinTree()//------------------------------中序线索化
	{
		BinTreeNode<T> *pre = NULL;
		create_inTreadBinTree(root,pre);
		pre->right = NULL;
		pre->rtag = TREAD;
	}
	void create_preTreadBinTree()//-----------------------------前序线索化
	{
		BinTreeNode<T> *pre = NULL;
		if(root!=NULL)
		{
			create_preTreadBinTree(root,pre);
			pre->right = NULL;
		    pre->rtag = TREAD;
		}
	}
	void create_postTreadBinTree()//----------------------------后序线索化
	{
		BinTreeNode<T> *pre = NULL;
		if(root!=NULL)
		{
			create_postTreadBinTree(root,pre);
		}
	}
public:              //----------------------------------------------中序线索化的一些功能实现
	BinTreeNode<T>* findfirst()//--------------------------------找头
	{
		return findfirst(root);
	}
	BinTreeNode<T>* findlast()//---------------------------------找尾
	{
		return findlast(root);
	}
	BinTreeNode<T>* findnext(BinTreeNode<T> *cur)//--------------找下一个
	{
		return findnext(root,cur);
	}
	BinTreeNode<T>* findprev(BinTreeNode<T> *cur)//--------------找上一个
	{
		return findprev(root,cur);
	}
	void InOrder()//中序线索化的中序遍历
	{
		InOrder(root);
	}
	void PreOrder()//前序线索化的前序遍历
	{
		PreOrder(root);
	}
protected:
	void PreOrder(BinTreeNode<T> *&p)
	{
		if(p == NULL)
			return;
		BinTreeNode<T> *cur = p;
		cout<<cur->data<<"-->";
		while(cur)
		{
			while(cur->ltag == LINK)
			{
				cur = cur->left;
				cout<<cur->data<<"-->";
			}
			while(cur->rtag == TREAD)
			{
				cur = cur->right;
				if(cur == NULL)
				{
				    cout<<"NULL";
					break;
				}
				else
					cout<<cur->data<<"-->";
			}
			if(cur != NULL)
			{
				if(cur->ltag == TREAD)
				{
					cur = cur->right;
					cout<<cur->data<<"-->";
				}
			}

		}
	}
	void InOrder(BinTreeNode<T> *&p)
	{
		if(p == NULL)
			return;
		BinTreeNode<T> *cur = p;
		while(cur)
		{
			while(cur->ltag == LINK)
			{
				cur = cur->left;
			}//找到最左边的头
			cout<<cur->data<<"-->";//然后输出
			if(cur->right)//------->必须有这句判断否则会出现访问冲突
			{
				while(cur->rtag == TREAD)
				{
					cur = cur->right;
					cout<<cur->data<<"-->";
				}
			}
			cur = cur->right;
		}
	}
	BinTreeNode<T>* findprev(BinTreeNode<T> *t,BinTreeNode<T> *cur)
	{
		if(t == NULL||cur == NULL)
			return NULL;
		if(cur->ltag == TREAD)
			return cur->left;
		return findlast(cur->left);
	}
	BinTreeNode<T>* findnext(BinTreeNode<T> *t,BinTreeNode<T> *cur)
	{
		if(t == NULL||cur == NULL)
			return NULL;
		if(cur->rtag == TREAD)
			return cur->right;
		return findfirst(cur->right);
	}
	BinTreeNode<T>* findlast(BinTreeNode<T> *t)
	{
		if(t == NULL)
			return NULL;
		while(t->rtag == LINK)
			t = t->right;
		return t;
	}
	BinTreeNode<T>* findfirst(BinTreeNode<T>*t)
	{
		if(t == NULL)
			return NULL;
		while(t->ltag == LINK)
			t=t->left;
		return t;

	}
	void create_Bintree(BinTreeNode<T> *&t)
	{
		T input;
		cin>>input;
		if(input == flag)
		{
			t = NULL;
		}
		else
		{
		//	t = new BinTreeNode<T>;
		//	t->data = input;
			t = new BinTreeNode<T>(input);
			create_Bintree(t->left);
			create_Bintree(t->right);
		}
	}
	void create_preTreadBinTree(BinTreeNode<T> *&bt,BinTreeNode<T> *&pre)
	{
		if(bt == NULL)
			return;
		if(bt->left == NULL)
		{
			bt->left = pre;
			bt->ltag = TREAD;
		}
		if(pre && pre->right==NULL)
		{
			pre->rtag = TREAD;
			pre->right = bt;
		}
		pre = bt;
		if(bt->ltag == LINK)
			create_preTreadBinTree(bt->left,pre);
		if(bt->rtag == LINK)
			create_preTreadBinTree(bt->right,pre);
	}
	void create_inTreadBinTree(BinTreeNode<T> *&bt,BinTreeNode<T> *&pre)
	{
		if(bt == NULL)
			return;
		create_inTreadBinTree(bt->left,pre);//一直递归到最左边
		if(bt->left == NULL)              //给最左边的结点的前驱一定是空
		{
			bt->ltag = TREAD;             //给他标记为线索化
			bt->left = pre;               //因为他是中序的头,并没有前驱。
		}
		if(pre!=NULL&&pre->right == NULL)
		{
			pre->rtag = TREAD;
			pre->right = bt;
		}
		pre = bt;
		create_inTreadBinTree(bt->right,pre);
	}
	void create_postTreadBinTree(BinTreeNode<T> *&bt,BinTreeNode<T> *&pre)
	{
		if (bt == NULL)
        {
            return;
        }
		create_postTreadBinTree(bt->left, pre);
        create_postTreadBinTree(bt->right, pre);
        if (bt->left == NULL)
        {
            bt->left = pre;
			bt->ltag = TREAD;
        }
        if (pre&&pre->right == NULL)
        {
			pre->rtag = TREAD;
            pre->right = bt;
        }
        pre = bt;	
	}
};


测试代码:

#include"treadbintree.h"
//ABC##DE##F##G#H##
int main()
{
	BinTreeNode<char> *put ;
	TreadBinTree<char> mytree;
        mytree.create_Bintree();           //先创建一棵普通的二叉树
//	mytree.create_inTreadBinTree();    //将二叉树线索化(中序)
	mytree.create_preTreadBinTree();   //将二叉树线索化(前序)
//	mytree.create_postTreadBinTree();  //将二叉树线索化(后序)
	put = mytree.findfirst();      
	cout<<(*put).getData()<<endl;
	put = mytree.findlast();
	cout<<(*put).getData()<<endl;
	put = mytree.findprev(put);
	put = mytree.findprev(put);//A
	put = mytree.findprev(put);
	put = mytree.findprev(put);//D
	put = mytree.findprev(put);
//	put = mytree.findparent(put);
//	put = mytree.findnext(put);
	if(put != NULL)//一定要加这个判断条件的,不然如果找的最后一个节点的下一个会出现访问冲突
		cout<<(*put).getData()<<endl;
	else
		cout<<"NULL"<<endl;
//	mytree.InOrder();
	mytree.PreOrder();
        return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值