现在的位置: 首页 > 综合 > 正文

C++线索二叉树

2013年10月03日 ⁄ 综合 ⁄ 共 4991字 ⁄ 字号 评论关闭

将二叉树线索化,实际上就是将其变为一个循环链表,下面的代码是采用中序的线索化,遍历也是中序遍历,都是基于中序的。

在中序遍历序列中求某一结点的前驱和后继的方法:(1)求某一结点的后继:如果所考虑的结点有右孩子,那么就要从该右孩子开始,顺着右孩子的左孩子域找下去,一直到左孩子域为空为止,最后这个结点就是所考虑结点的后继;如果所考虑的结点没有右孩子,那么就要遍历二叉树。(2)求某一结点前驱:如果所考虑结点有左孩子,那么就要从该左孩子开始,顺着该左孩子的右孩子链域找下去,一直到右孩子的链域为空为止,最后这个结点就是所考虑结点的前驱;然后该结点没有左孩子,那么就要遍历二叉树。

下面代码中还有一个要说的就是用来辅助搜索的Address结构体数组,一开始我本来是乡写一个函数,直接就是在遍历的过程中搜索指定数值的结点,但是有时对有时错,搞了一个下午都不知怎么搞好,就放弃了,采用这个结构体数组的方法,简单一些,那个等以后老师讲的时候再看看老师会怎么实现吧,可能会有灵感。

 

文件"tree.h"

#include<iostream>
using namespace std;

class ThreadTree;//线索二叉树

class Thrnode
{
private:
	int data;
	int ltag;	//ltag为0:表示lchild为一般二叉树的指针,指向其左子树
	int rtag;	//ltag为1:表示lchild为指向此结点的前驱的指针,rtag同理
	Thrnode *lchild;
	Thrnode *rchild;
	
	friend class ThreadTree;
};

int num=0;//记录结点数目
struct Address		//辅助搜索
{
	int data;
	Thrnode *p;
}ad[100];

class ThreadTree
{
private:
	Thrnode *root;
public:
	ThreadTree()
	{
		root=0;
	}

	Thrnode *Get_Root()
	{
		return root;
	}

	int Get_data(Thrnode *p)
	{
		return p->data;
	}

	Thrnode *Create_Tree(Thrnode *r)	//先序建立二叉树
	{
		int d;
		cout<<"输入数据(0代表空):";
		cin>>d;
		if(d==0)
			return 0;
		else
		{
			num++;
			r=new Thrnode;
			r->ltag=0;
			r->rtag=0;
			r->data=d;
			r->lchild=Create_Tree(r->lchild);
			r->rchild=Create_Tree(r->rchild);
		}
		root=r;
		return r;
	}

	void In_Threading(Thrnode *p,Thrnode *&pre)
	{
		//以指针p所指向的二叉树进行中序遍历,遍历过程中进行线索化
		//pre指针是p的前驱指针
		if(p)
		{
			In_Threading(p->lchild,pre);//左子树线索化
			if(!p->lchild) //若p的左子树为空,给p结点加前驱线索
			{
				p->ltag=1;
				p->lchild=pre;
			}
			else
				p->ltag=0;
			if(pre && !pre->rchild)
			{
				pre->rtag=1;
				pre->rchild=p;
			}
			pre=p;
			In_Threading(p->rchild,pre); //右子树线索化
		}

	}

	Thrnode *InOrder_Threading(Thrnode *r) //将二叉树线索化,按中序遍历的顺序
	{
		//遍历二叉树,并将其中序线索化,其中,Thrt指针指向头结点,r指向根节点
		Thrnode *pre=NULL;
		Thrnode *Thrt;
		Thrt=new Thrnode;
		Thrt->ltag=0;
		Thrt->rtag=1;
		Thrt->rchild=Thrt;//初始化时,让头结点的右指针指向自己
		if(!r)
			Thrt->lchild=Thrt;	//若为空树,左指针也指回自己
		else
		{
			Thrt->lchild=r;
			pre=Thrt;
			In_Threading(r,pre);	//pre是r的前驱指针

			//从上面的函数出来时,pre指在最后一个结点处
			pre->rchild=Thrt;
			pre->rtag=1;
			//最后一个结点的线索化

			Thrt->rchild=pre;
		}
		cout<<"二叉树线索化 完成~~"<<endl;
		return Thrt;
	}
	
	void InOrder_Thr(Thrnode *Thrt)	//中序遍历线索二叉树
	{
		//遍历的同时,将相对应的值和结点指针存入结构体,便于搜索
		int count=0;
		Thrnode *r;
		r=Thrt->lchild;
		while(r!=Thrt)
		{
			while(r->ltag==0)
				r=r->lchild;
			cout<<r->data<<"  ";
			ad[count].data=r->data;
			ad[count].p=r;
			count++;
			while(r->rtag==1 && r->rchild!=Thrt)
			{
				r=r->rchild;
				cout<<r->data<<"  ";
				ad[count].data=r->data;
				ad[count].p=r;
				count++;
			}
			r=r->rchild;
		}
	}

	Thrnode *Search(int d)	//搜索
	{
		for(int i=0;i<num;i++)
			if(ad[i].data==d)
				return ad[i].p;
	}

	void Prior_Thr(Thrnode *Thrt,Thrnode *t,Thrnode *&p)  //求结点前驱
	{
		//p返回结点t的前驱
		p=t->lchild;
		if(p==Thrt)
		{
			cout<<"给定的结点是第一个结点,不存在前驱"<<endl;
			return ;
		}
		if(t->ltag==0)
			while(p->rtag==0)
				p=p->rchild;
	}

	void Next_Thr(Thrnode *Thrt,Thrnode *t,Thrnode *&p)	//求结点后继
	{
		p=t->rchild;
		if(p==Thrt)
		{
			cout<<"该结点为最后一个结点,无后继"<<endl;
			return ;
		}
		if(p->rtag==0)
			while(p->ltag==0)
				p=p->lchild;
	}

	void Insert_Lchild(Thrnode *Thrt,Thrnode *t,int d)	//作为左孩子插入
	{
		/*
		将结点值为d的结点插入t后面,作为t的左孩子
		如果t本来的无左孩子,那么直接插入即可
		如果t有左孩子,那么:
		t的左孩子在新的节点q插入后,作为q的左孩子,因此q->ltag=0;
		将新结点q作为t的左孩子
		求出新的结点q的前驱,修改q的前驱结点的rchild域,使它的后继为q
		*/
		
		Thrnode *q=new Thrnode;
		q->data=d;
		
		q->lchild=t->lchild;
		q->ltag=t->ltag;
		
		q->rchild=t;
		q->rtag=1;
		
		t->lchild=q;
		t->ltag=0;

		if(q->ltag==0)
		{
			Thrnode *p;
			Prior_Thr(Thrt,q,p);
			p->rchild=q;
		}
		//若q->rtag为0,那么就要找出q的前继
		cout<<"插入为结点值为:"<<t->data<<"的左孩子成功"<<endl;
		num++;
	}

	void Insert_Rchild(Thrnode *Thrt,Thrnode *t,int d)	//作为右孩子插入
	{
		//思路和上面的左孩子一样
		Thrnode *q=new Thrnode;
		q->data=d;
		
		q->rchild=t->rchild;
		q->rtag=t->rtag;

		q->lchild=t;
		q->ltag=1;

		t->rchild=q;
		t->rtag=0;

		if(q->rtag==0)
		{
			Thrnode *p;
			Next_Thr(Thrt,q,p);
			p->lchild=q;
		}
		cout<<"插入为结点值:"<<t->data<<"的右孩子成功"<<endl;
		num++;
	}

};

测试函数"main.cpp"

#include"tree.h"

int main()
{
	ThreadTree t;
	Thrnode *r=t.Get_Root(),*k;
	k=t.Create_Tree(r);

	cout<<"_____二叉树线索化_____"<<endl;
	Thrnode *Thrt=0;
	Thrt=t.InOrder_Threading(k);

	if(Thrt)
	{
		cout<<"中序遍历线索二叉树为:";
		t.InOrder_Thr(Thrt);
		cout<<endl;
	}	

	int data1,data2;
	cout<<"输入你要在值为多少的结点处插入作为其左孩子:";
	cin>>data1;
	Thrnode *p=0;
	p=t.Search(data1);
	if(!p)
		cout<<"找不到插入点"<<endl;
	else
	{
		cout<<"要插入的结点地址为:"<<p<<endl;
		cout<<t.Get_data(p)<<endl;
		
		cout<<"输入你要插入的新结点的值:";
		cin>>data2;
		cout<<"____将新结点插入为左孩子____"<<endl;
		t.Insert_Lchild(Thrt,p,data2);
	}

	cout<<"中序遍历二叉树为:";
	t.InOrder_Thr(Thrt);
	cout<<endl;
	
	int data3,data4;
	cout<<"输入你要在值为多少的结点处插入作为其右孩子:";
	cin>>data3;
	Thrnode *f=0;
	f=t.Search(data3);
	if(!f)
		cout<<"找不到插入点"<<endl;
	else
	{
		cout<<"要插入的结点地址为:"<<f<<endl;
		cout<<t.Get_data(f)<<endl;
		cout<<"输入你要插入的新结点的值:";
		cin>>data4;
		cout<<"____将新结点插入为右孩子____"<<endl;
		t.Insert_Rchild(Thrt,f,data4);
	}
	
	cout<<"中序遍历二叉树为:";
	t.InOrder_Thr(Thrt);
	cout<<endl;

	cout<<"结点值为:"<<data1<<"的前驱结点值为:";
	Thrnode *s=new Thrnode;
	t.Prior_Thr(Thrt,p,s);
	cout<<t.Get_data(s)<<endl;

	cout<<"结点值为:"<<data3<<"的后继结点值为:";
	Thrnode *x=new Thrnode;
	f=t.Search(data3);
	t.Next_Thr(Thrt,f,x);
	cout<<t.Get_data(x)<<endl;
	
	return 0;
}

下面是输出结果,输入依然是 5 3 2 1 0 0 0 4 0 0 8 6 0 7 0 0 9 0 0 生成的二叉树图像在之前那篇二叉树的日志里面有,这里不再贴出

输入数据(0代表空):5
输入数据(0代表空):3
输入数据(0代表空):2
输入数据(0代表空):1
输入数据(0代表空):0
输入数据(0代表空):0
输入数据(0代表空):0
输入数据(0代表空):4
输入数据(0代表空):0
输入数据(0代表空):0
输入数据(0代表空):8
输入数据(0代表空):6
输入数据(0代表空):0
输入数据(0代表空):7
输入数据(0代表空):0
输入数据(0代表空):0
输入数据(0代表空):9
输入数据(0代表空):0
输入数据(0代表空):0
_____二叉树线索化_____
二叉树线索化 完成~~
中序遍历线索二叉树为:1  2  3  4  5  6  7  8  9
输入你要在值为多少的结点处插入作为其左孩子:4
要插入的结点地址为:00382478
4
输入你要插入的新结点的值:12
____将新结点插入为左孩子____
插入为结点值为:4的左孩子成功
中序遍历二叉树为:1  2  3  12  4  5  6  7  8  9
输入你要在值为多少的结点处插入作为其右孩子:7
要插入的结点地址为:00382550
7
输入你要插入的新结点的值:13
____将新结点插入为右孩子____
插入为结点值:7的右孩子成功
中序遍历二叉树为:1  2  3  12  4  5  6  7  13  8  9
结点值为:4的前驱结点值为:12
结点值为:7的后继结点值为:13
Press any key to continue

 

【上篇】
【下篇】

抱歉!评论已关闭.