版权声明:本文为博主原创文章,转载请注明出处。 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;
}
今天就到这里啦~~~