线索树任意节点插入左右孩子

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/yg_hou/article/details/51107956

转载请注明出处

线索树节点插入方法

一.问题分析

          1.以下分析以插入右孩子为例,插入左孩子的方法类似,只需将插入右孩子的方法中方向换掉即可。


       2.假设被插入节点为s,插入的节点为r。在该节点处插入一个右孩子分为两种情况,即s有右子树s没有右子树

            1)   s没有右子树时,情况比较简单。显然,只需将①r的rchild执行s的rchild,②s的rchild指向r,③r的lchild指向s,

          注意以上三步操作的顺序不可颠倒。 此种情况类似于链表的操作。

         2) s有右子树时,还需要对s的右子树的指针域进行操作。关键的一步为:令原来s的中根顺序后继节点s$的lchild指向r.

               其实s$就是s原来右子树的最左节点。s$在插入前lchild是指向s的。

         以上大家最好画图理解。           

二.关键函数

     有了上面的分析,相信大家能写出函数了。

      以下代码中出现的inNext(node* n) 和inPre(node* n) 函数为中序遍历的后继结点和前驱结点函数

      

//插入右孩子
void rInsert(node* s,node* r)
{
	node* w;
	r->rchild=s->rchild;
	r->rtag=s->rtag;
	r->lchild=s;
	r->ltag=false;//新插入的节点木有左子树,所以lchild指向的是父节点
	s->rchild=r;
	s->rtag=true;//原节点的右孩子为新插入的节点
	if(r->rtag==true){
		//这里是神马意思呢∑q|?Д?|p,就是如果被插节点s有右子树 ,
		//找出被插节点s的的next位置,即右子树中的最左节点,令其lchild指向新添加的节点r 
		//因为插入前该最左节点的lchild指向的是原来节点s 
		w=inNext(r);
		w->lchild=r;
	}
}

//插入左孩子
void lInsert(node* s,node* l)
{
	node* w;
	l->lchild=s->lchild;
	l->ltag=s->ltag;
	l->rchild=s;
	l->rtag=false;
	s->lchild=l;
	s->ltag=true;
	if(l->ltag==true){//与插入右孩子方法相似,只需把左右方向对调即可 
		w=inPre(l);
		w->rchild=l;
	}
} 

三.完整代码

      以下给出了二叉树操作的完整代码,包括了测试用例。

/*
题目:	
	在中序线索二叉树中插入一个结点Q作为树中某个结点P的左孩子,试给出相应的算法。
	要求:
		1、	定义中序线索二叉树的型THTREE以及基本操作。
		2、	定义函数void LInsert(THTREE P, THTREE Q); 实现题目要求的操作。
		在主函数中,利用操作RInsert和LInsert构造一个线索二叉树,
		并中序输出二叉树的结点的元素,验证结果。
创建时间:04/09/2016
		kaiser  NJTECH
*/
#include<iostream>
#include<iomanip>
#include<cmath>
#include<cstdlib>
#include<string>
using namespace std;

typedef int elementtype;
struct node{//节点的型 
	node* lchild;
	node* rchild;
	bool ltag;
	bool rtag;
	elementtype element;
};
typedef node* head;//指向树根root
typedef node* tree;//指向线索树的根节点 

void makeNull(head& h)//将线索二叉树置空 
{
	h->lchild=h;
	h->ltag=false;
	h->rchild=h;
	h->rtag=true; 
}
head pointTotree(head& h,tree& t)//令head指向tree,注意head指向的并不是根节点,tree指向根节点 
{
	h->lchild=t;
	h->rchild=h;
	h->ltag=true;
	h->rtag=true; 
	return h;
} 

//中根遍历的下一个节点
node* inNext(node* p)
{
	node* q=p->rchild;
	if(p->rtag==true)//如果有右子树,找出右子树的最左节点 
		while(q->ltag==true)
			q=q->lchild;
	return q;
} 
//中根遍历的上一个节点 
node* inPre(node* p)
{
	node *q= p->lchild; 
	if(p->ltag==true)//如果P的左子树存在,则其前驱结点为左子树的最右结点
		while(q->rtag==true) 
			q=q->rchild; 
	return q;//左子树的最右结点
}
//中序遍历 
void thInOrder(head h)
{
	node* temp;
	temp=h;
	do{
		temp=inNext(temp);
		if(temp!=h)
			cout<<temp->element<<" ";
	}while(temp!=h);
} 

//插入右孩子
void rInsert(node* s,node* r)
{
	node* w;
	r->rchild=s->rchild;
	r->rtag=s->rtag;
	r->lchild=s;
	r->ltag=false;//新插入的节点木有左子树,所以lchild指向的是父节点
	s->rchild=r;
	s->rtag=true;//原节点的右孩子为新插入的节点
	if(r->rtag==true){
		//这里是神马意思呢∑q|?Д?|p,就是如果被插节点s有右子树 ,
		//找出被插节点s的的next位置,即右子树中的最左节点,令其lchild指向新添加的节点r 
		//因为插入前该最左节点的lchild指向的是原来节点s 
		w=inNext(r);
		w->lchild=r;
	}
}

//插入左孩子
void lInsert(node* s,node* l)
{
	node* w;
	l->lchild=s->lchild;
	l->ltag=s->ltag;
	l->rchild=s;
	l->rtag=false;
	s->lchild=l;
	s->ltag=true;
	if(l->ltag==true){//与插入右孩子方法相似,只需把左右方向对调即可 
		w=inPre(l);
		w->rchild=l;
	}
} 
int main()
{
	head h=new node;
	node* root=new node;
	node* lc=new node;
	node* rc=new node;
	node* c=new node;
	
	root->element=1;
	lc->element=2;
	rc->element=3;
	c->element=4;
	
	h->rchild=root;
	h->lchild=h;
	h->ltag=true;
	h->rtag=true;
	
	root->lchild=h;
	root->rchild=h;
	root->ltag=false;
	root->rtag=false;
	//构造线索树213 
	lInsert(root,lc);
	rInsert(root,rc);
	thInOrder(h);
	cout<<endl;
	
	//root左边插入C
	lInsert(root,c);
	thInOrder(h);
	 
  return 0;
}

今天就到这里啦~~~

       

猜你喜欢

转载自blog.csdn.net/yg_hou/article/details/51107956