二叉树的后继节点

一、二叉树的后继节点:

简单来讲就是在中序遍历中某节点的下一个节点。

二、如何判断后继节点
  1. 如果一个节点有右孩子,那么后继节点就是该节点的右子树的最左叶节点
    在这里插入图片描述
    假设节点为1,那么后继节点为6(最左叶节点)

2.如果没有右孩子说明以这个节点为根节点的子树遍历完成,应该访问父节点,若该节点是右节点,说明以父节点为根节点的子树遍历完成,再次访问祖父节点,以此类推,直到改节点为左孩子,或者父节点为null。

三、代码如下:
public class BinNode{
	int value;
	BinNode left;
	BinNode right;
	BinNode parent;
	public BinNode(int value){
		this.value = value;
	}
}
public class BinTree{
	public BinNode nodeSucc(BinNode node){
		if(node.right){  // 若有右节点
			node = node.right;  
			while(node.left) node = node.left;  // 获取右子树的最左节点
		}else{
			while(node.parent.left != node){  // 如果该节点为父节点的右节点
				node = node.parent;  // 将节点变为父节点 
				if(!node.parent) break;	// 若到达根节点,退出
			}
			node = node.parent;	
		}
		return node;
	}
}
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
#include <iostream> #include<stack> #include<queue> using namespace std; const int LH=1; //左子树比右子树高1 const int EH=0; //左右子树一样高 const int RH=-1;//右子树比左子树高1 const int MAX_NODE_NUM=20; //结点数目上限 class AvlNode { int data; int bf; //平衡因子 AvlNode *lchild; AvlNode *rchild; friend class AVL_Tree; }; class AVL_Tree { public: int Get_data(AvlNode *p) { return p->data; } void Create_AVl(AvlNode *&T) //建树 { cout<<"输入平衡二叉树的元素,输入-1代表结束输入:"; int num[MAX_NODE_NUM]; int a,i=0; while(cin>>a && a!=-1) { num[i]=a; i++; } if(num[0]==-1) { cout<<"平衡树为空"<<endl; T=NULL; return; } int k=i; bool taller=false; for(i=0;i<k;i++) Insert_Avl(T,num[i],taller);//逐个进行插入,插入过程看下面的示意图 cout<<"_____建树完成____"<<endl; } void L_Rotate(AvlNode *&p) { //以p为根节点的二叉排序树进行单向左旋处理 AvlNode *rc=p->rchild; p->rchild=rc->lchild; rc->lchild=p; p=rc; } void R_Rotate(AvlNode *&p) { //以p为根节点的二叉排序树进行单向右旋处理 AvlNode *lc=p->lchild; p->lchild=lc->rchild; lc->rchild=p; p=lc; } void Left_Balance(AvlNode *&T) { //以T为根节点的二叉排序树进行左平衡旋转处理 AvlNode *lc,*rd; lc=T->lchild; switch(lc->bf) { case LH: //新结点插在T的左孩子的左子树上,做单向右旋处理 T->bf=lc->bf=EH; R_Rotate(T); break; case RH: //新结点插在T的左孩子的右子树上,要进行双旋平衡处理(先左后右) rd=lc->rchild; switch(rd->bf) { case LH: //插在右子树的左孩子上 T->bf=RH; lc->bf=EH; break; case EH: T->bf=lc->bf=EH; break; case RH: T->bf=EH; lc->bf=LH; break; } rd->bf=EH; L_Rotate(T->lchild);//先对T的左子树进行单向左旋处理 R_Rotate(T); //再对T进行单向右旋处理 } } void Right_Balance(AvlNode *&T) { //以T为根节点的二叉排序树进行右平衡旋转处理 AvlNode *rc,*ld; rc=T->rchild; switch(rc->bf) { case RH: //新结点插在右孩子的右子树上,进行单向左旋处理 T->bf=rc->bf=EH; L_Rotate(T); break; case LH: //新结点插在T的右孩子的左子树上,要进行右平衡旋转处理(先右再左) ld=rc->lchild; switch(ld->bf) { case LH: T->bf=LH; rc->bf=EH; break; case EH: T->bf=rc->bf=EH; break; case RH: T->bf=EH; rc->bf=RH; break; } ld->bf=EH; R_Rotate(T->rchild);//先对T的右子树进行单向右旋处理 L_Rotate(T); //再对T进行单向左旋处理 } } bool Insert_Avl(AvlNode *&T,int num,bool &taller) //插入 { //若在平衡二叉树中不存在结点值和num一样大小的结点 //则插入值为num的新结点,并返回true //若因为插入而使得二叉排序树失去平衡,则做平衡旋转处理 //taller反映树是否长高 if(!T) { //插入新结点,树长高,taller为true T=new AvlNode; T->data=num; T->lchild=T->rchild=NULL; T->bf=EH; taller=true; } else { if(num==T->data) { //不重复插入 taller=false; return false; } if(num<T->data) //继续在T的左子树中进行搜索 { if(!Insert_Avl(T->lchild,num,taller))//插入不成功 return false; if(taller) //已插入T的左子树,且左子树长高 { switch(T->bf) { case LH: /*————————————————————— / 插入前左子树高于右子树,需要进行做平衡处理 / 不管是单向左旋处理,还是先左后右平衡处理 / 处理结果都是使得插入新结点后,树的高度不变 /—————————————————————*/ Left_Balance(T); taller=false; break; case EH: //插入前左右子树等高,现在插入新街点后,左子树比右子树高 T->bf=LH; taller=true; break; case RH: //插入前右子树比左子树高,现在新结点插入左子树后,树变为左右子树等高 T->bf=EH; taller=false; break; } } } else { //num>T->data 在T的右子树中继续搜索 if(!Insert_Avl(T->rchild,num,taller)) return false; if(taller) { switch(T->bf) { case LH: //插入前左子树比右子树高,现在插入T的右子树后,左右子树等高 T->bf=EH; taller=false; break; case EH: //插入前左右子树等高,现在插入后,右子树比左子树高 T->bf=RH; taller=true; break; case RH: //插入前右子树比坐子树高,插入后,排序树失去平衡,需要进行右平衡处理 Right_Balance(T); taller=false; break; } } } } return true; } bool Search_Avl(AvlNode *T,int num,AvlNode *&f,AvlNode *&p) //搜索 { //用p带回查找到的顶点的地址,f带回p的双亲结点 p=T; while(p) { if(p->data==num) return true; if(p->data>num) { f=p; p=p->lchild; } else { f=p; p=p->rchild; } } return false; } void Delete_AVL(AvlNode *&T,int num) //删除,删除后没有回溯到根节点,算法有错,待日后修改完善,有心的朋友可以自己加一个栈或者其他方式来实现 { /*--------------------------------------------------------- / 从树中删除一个节点后,要保证删后的树还是一棵平衡二叉树, / 删除前,首先是在树中查找是否有这个结点,用p指向该结点, / 用f指向p的双亲结点,这个结点在树中的位置有下面四种情况: / / 1:如果p指向的结点是叶子结点,那么直接将f指针的左子树或者 / 右子树置空,然后删除p结点即可。 / / 2:如果p指向的结点是只有左子树或右子树,那么只需要让p结点 / 原来在f中的位置(左子树或右子树)用p的子树代替即可。 / 代替后,要修改f的平衡因子,在失去平衡的时候,要调用相应的 / 做平衡旋转或右平衡旋转进行恢复. / / 3:如果p所指向的结点是根节点,那么直接将根节点置空 / / 4:如果p所指向的结点左右子树都非空,为了删除p后原序列的顺 / 序不变,就需要在原序列中先找出p的直接前驱(或者直接后继) / 结点用那个结点的值来代替p结点的值,然后再删掉那个直接前 / 驱(或者直接后继)结点。 / 其中s指向的是要删除的结点,也就是p的直接前驱,q指向的是 / s的双亲结点,此时,应该看s的平衡因子,在会出现失去平衡的 / 情况时,就要根据实际情况采用左平衡旋转或是右平衡旋转,让 / 树恢复平衡,这点和插入操作时是相对应的。 / / 在中序遍历序列中找结点的直接前驱的方法是顺着结点的左孩子 / 的右链域开始,一直到结点右孩子为空为止。 /---------------------------------------------------------*/ AvlNode *f=NULL; AvlNode *p=NULL; AvlNode *q=NULL; AvlNode *s=NULL; if(Search_Avl(T,num,f,p)) { if(p->lchild && p->rchild) //左右子树均存在时 { q=p; s=p->lchild; while(s->rchild) { q=s; s=s->rchild; } p->data=s->data; if(q!=p) { //q结点的右子树高度减少1 //所以平衡因子会+1 q->rchild=s->lchild; switch(q->bf) { //删除前右子树高,现在就变成一样高 case RH: q->bf=EH; break; //删除前等高,现在就变成左子树比右子树高 case EH: q->bf=LH; break; //删除前左子树高,现在左子树又高了一,所以失去平衡 case LH: q->bf=EH; Left_Balance(q); break; } } else { //p的左子树的右子树为空时 //q结点也就是p结点,由于s的右子树为空 //所以q结点的左子树高度降低1 //平衡因子-1 q->lchild=s->lchild; switch(q->bf) { case LH: q->bf=EH;break; case EH: q->bf=RH;break; case RH: q->bf=EH; Right_Balance(q); break; } } delete s; cout<<"删除结点成功"<<endl; return ; } else { if(!p->lchild) { q=p; p=p->rchild; } else { q=p; p=p->lchild; } if(!T) { T->bf=EH; T=p; } else if(q==f->lchild) { f->lchild=p; switch(f->bf) { case LH: f->bf=EH; break; case EH: f->bf=RH; break; case RH: f->bf=EH; Right_Balance(f); break; } } else { f->rchild=p; switch(f->bf) { case RH: f->bf=EH; break; case EH: f->bf=LH; break; case LH: f->bf=EH; Left_Balance(f); break; } } delete q; cout<<"删除结点成功"<<endl; return; } } else { cout<<"要删除的结点不存在"<<endl; return; } } InOrder_Traverse(AvlNode *T) //中序遍历 { stack<AvlNode *> s; AvlNode *p=T; while(p || !s.empty()) { if(p) { s.push(p); p=p->lchild; } else { p=s.top(); s.pop(); cout<<p->data<<" "; p=p->rchild; } } } void Level_Traverse(AvlNode *T) //层次遍历 { queue<AvlNode *> q; AvlNode *p=T; q.push(p); while(!q.empty()) { p=q.front(); q.pop(); cout<<p->data<<" "; if(p->lchild) q.push(p->lchild); if(p->rchild) q.push(p->rchild); } } }; //测试文件"main.cpp" //#include"tree.h" int main() { AVL_Tree tree; AvlNode *root=NULL; cout<<"____建立平衡二叉树____"<<endl; tree.Create_AVl(root); cout<<"中序遍历二叉树为:"; tree.InOrder_Traverse(root); cout<<endl; cout<<"层次遍历二叉树为:"; tree.Level_Traverse(root); cout<<endl; int num; bool taller=false; cout<<"输入你要插入的结点的值:"; cin>>num; tree.Insert_Avl(root,num,taller); cout<<"中序遍历二叉树为:"; tree.InOrder_Traverse(root); cout<<endl; AvlNode *f=NULL; AvlNode *p=NULL; cout<<"输入你要搜索的结点的值:"; cin>>num; if(tree.Search_Avl(root,num,f,p)) { cout<<"查找得到的结点值为:"<<tree.Get_data(p)<<"的地址为:"<<p<<endl; if(f==NULL) cout<<"因为结点"<<tree.Get_data(p)<<"是根结点,所以没有双亲结点"<<endl; else cout<<"该结点的双亲结点的值为:"<<tree.Get_data(f)<<endl; } else cout<<"查找的结点不存在"<<endl; cout<<"输入你要删除的结点的值:"; cin>>num; tree.Delete_AVL(root,num); cout<<"中序遍历二叉树为:"; tree.InOrder_Traverse(root); cout<<endl; return 0; }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值