算法笔记(树)

树的算法

1.基于后序遍历

1.求i,j最近的公共祖先结点(顺序存储)
2.树的后序遍历(非递归算法)
3.求i,j最近的公共祖先结点(链式存储)
13.求值为x的结点的所有祖先

2.基于层次遍历

4.求树的高度(非递归+递归),求某节点所在层次也用这个非递归就行
5.求树的宽度
6.判断是否是完全二叉树

3.基于递归构建二叉链表

7.给先序和中序(数组),构建二叉链表
8.给满二叉树的先序,求后序

4.前、中、后根遍历都可的算法

9.求双分支节点个数,叶子节点个数,单分支节点个数
10.交换所有结点的左右子树
11.求先序遍历的第k个结点
12.找到所有值为x的结点,并删除它和其子树

14.把所有叶子节点从左到右串起来,变成一个链表
15.判断两个二叉树相似
17.所有叶子的带权路径WPL之和
18.把二叉树转化为中缀表达式(带括号)

5.线索二叉树相关算法

16.中序线索二叉树查找指定结点在后序序列的前驱结点

6.孩子兄弟链表表示树

19.孩子兄弟链表存储的森林的叶子节点个数
20.孩子兄弟链表存储的的深度
21.已知一棵树的层次序列以及每个节点的度,构造孩子兄弟链表

7.二叉排序树相关算法

22.判断是否是二叉排序树
23.二叉排序树的查找,插入,构造
24.从大到小输出BST中所有值不小于k的关键字
25.求BST中第k小的数,返回结点指针

Question 1:
任意两个结点必然存在最近公共祖先,最坏情况是根节点。且从最近公共祖先结点到根节点所经过的结点都是公共的。

这是顺序存储,双亲和孩子的位置可以互相表示,所以算法简单
若链式存储,孩子无法找双亲,就稍微难点,在后面的树的遍历中会涉及到该算法。

//查找i,j的最近公共祖先	

ElemType Same_Ancestor(SqTree T,int i,int j){	(非递归)

	if(T[i]!='#'&&T[j]='#'){	//结点存在
		while(i!=j){		//未找到公共祖先,继续循环,当i==j,即找到公共祖先
			if(i>j) i=i/2;	//谁编号大,说明它的层数可能更低,谁编号大谁往上找
			else j=j/2;
		}
		return T[i];	//最终肯定有返回值,最坏情况是根
	}
}


ElemType Same_Ancestor(SqTree T,int &i,int &j){		(递归)
	if(i==j) return T[i];
	if(i>j) 
		Same_Ancestor( T,i/2,j);
	else 
		Same_Ancestor( T,i,j/2);
}

Question 2:
给栈元素加一个属性,普通的栈只是存树节点,现加入flag标记(0表示访问了左子树,1表示访问了左右),即只有flag=1时才能进行visit访问操作。

struct elem{			//定义栈元素,包括树结点和标记
	BiNode *data;
	int flag;
}elem;

void PostTraverse(BiTree bt){
//1.准备工作,栈,工作指针
	stack s;
	BiNode *p=bt;

//2.开始循环,先访问左子树
	while(!s.empty()||p){
		if(p){
			elem.data=p;	
			elem.flag=0;	//构造一个完整的栈元素,把访问到的树结点信息存入栈	
			
			s.push(elem);	
			p=p->lchild;
		}
		
		elem=s.pop(); 
		p=elem.data;	//先出栈,访问一下信息
		
		if(elem.flag==0){	//需要再次入栈,且修改flag为1
			elem.flag=1;
			s.push(elem);
			p=p->rchild; 	//左子树访问完了,该右子树了
		}
		else{		//即flag==1,右子树访问过了,可以访问当前节点了
			visit(p);
			p=NULL;//重置p是为了,确保下一次循环的出栈
		}
		
	}
}

Question 3:
采用后序遍历的非递归算法,
当访问到某结点时,栈中所有元素均为该节点的祖先。
1.假设 i 在 j 的左边,后序遍历必定先遍历到结点 i,此时栈中都是 i 的祖先。
2.再将栈复制到另一个辅助栈中。
3.继续遍历到结点 j 时,将栈中元素从栈顶开始逐个到辅助栈去匹配。第一个匹配成功的元素就是最近公共祖先。(根结点在栈底)

typedef struct{
	BiTree t;
	int tag;
}stack;

stack s[],s1[];	//整了个顺序栈
//下面开始算法,返回值为最小公共祖先结点。
BiTree Same_Ancestor(BiTree bt,BiNode *i,BiNode *j){
	top=0;
	BiNode *p=bt;
	while(top>0||p){	//这是总的大循环,工作指针p进行遍历
		if(p){
			top++;		//这三行表示入栈
			s[top].t=p;
			s[top].flag=0;
			
			p=p->lchid;	//一路向左
		}
//这是一个内部小循环,进行统一退栈
		while(top!=0&&s[top].tag==1){	//相当于修改visit操作

//此时找到了 i 结点
			if(s[top].t==i){		//假设i在j左边,即i先找到,把此时的栈复制一份,
				for循环,数组赋值我就不写了;
			}
			
//此时找到了 j 结点
			if(s[top].t==j){
				for(int k=top;k>0;k--)
					for(int m=top1;m>0;m--)
						if(s1[m].t==s[k].t)	//字符串匹配。最简单的二重循环暴力法	
							return s[k].t; //匹配成功,返回
			}
			
			top--;  //统一退栈操作,若是1就退栈,若是0 根本不循环
							//当前结点不是 i也不是 j,前面两个if不走,只退栈(空遍历)
		
		} //到这统一退栈的whle结束
		
		//栈不空,又不能访问,只能修改以下flag,向右边遍历
		if(top!=0){		//栈不空
				s[top].tag=1;
				p=s[top].t->rchild;
		(//为什么没有入栈操作,不是二次入栈吗?
		//top--;然后再top++;这不是费事吗,顺序栈可以直接访问,不需要取出来再放进去)
		}

	}
	
}

Question 4
非递归:采用层次遍历的算法,
设置level记录当前所在层数;
设置last保存当前层的最右边的结点
每次层次遍历出队时与last比较,相等则层数加1,并让last变成下一层的最右系结点。

int Depth(BiTree T){
	if(T==null)	
		return 0; //树空
	
	int front=-1,rear=-1;  //层次遍历需要队列,用顺序队列,用下标方便表示结点的关系
	int last=0,level=0;		
	BiTree Q[Maxsize];
	BiTree p;			//以上声明必要的变量,p为工作指针,接收出队的结点
	
	Q[++rear]=T; //根节点入队
	while(front<rear){		//队不空则循环
		p=Q[++front];   //出队。正要访问 p
		if(p->lchild)
			Q[++rear]=p->lchild;
		if(p->rchild)
			Q[++rear]=p->rchild;
//以上是层序遍历的代码
//以下是扣题代码,(核心)
		if(front==last){	//当前要出队的结点下标等于last,即当前最右边结点要被访问
			level++;
			last=rear; //为什么把队尾赋给last??
			//若当前结点为该层最右,他的右孩子(若存在)必为下一层的最右,队尾就是下一层的最后一个结点。
		} //if()	

		//可以在while循环中加一个判断,如果遍历到了所求结点,立即返回level(当前level),而不需要全部遍历完(整个树的高度)
	} //while()
	
	return level;
}


递归算法
int Depth(BiTree T){
	if(T==null) 
		return 0;
	else{
		int left=Depth(T->lchild);
		int right=Depth(T->rchild);
		return left>right?left+1:right+1;
	}
}

求宽度和求高度的非递归思想一致。
利用层序遍历,last,level-----变成width,记录所以层中的最大的宽度

int Width(BiTree T){
	//代码完全一致,只是最后的核心代码不同!
//1.声明变量 
2.while队不空,循环层序遍历  
3.遍历每一个结点时进行判断是否到头==last,更新width(核心)

	if(T==null)return 0;
	int front=-1,rear=-1;
	int width=1.last=0;	//width初始化为1,不然只有一个结点时,核心函数运行不是正确答案
	BiTree Q[Maxsize];
	BiTree p;
	Q[++rear]=T;
	while(front<rear){
		p=Q[++front];
		if(p->lchild)
			Q[++rear]=p->lchild;
		if(p->rchild)
			Q[++rear]=p->rchild;

		if(front==last){
		
			if(rear-last>width)		//width的赋值要先于last,因为用到了老last 
					width=rear-last;
					
			last=rear;	//指向下一层最右
		}
	}
}

Question 6:
基于层次遍历,将所有结点加入队列,入队时无需判断左右孩子是否不空,空的也加入;
当出队时(遍历到当前结点)遇到了空,查看其后是否有非空结点,若有则不是完全二叉树。

bool IsComplete(BiTree T){
	if(!T) return 1;	//空树是满二叉树
	
	Queue Q;
	InitQueue(Q);
	BiTree p=T;
	EnQueue(Q,T);
	while(!IsEmpty(Q)){
		DeQueue(Q,p);
		if(p){
			EnQueue(Q,p->lchild);
			EnQueue(Q,p->rchild);
		}
		else{
			while(!IsEmpty(Q)){		//在这里加入了判断,若p为空就会跳到这里执行while
				DeQueue(Q,p)		//不断遍历空结点后面的结点,一旦发现有非空结点,则不是
				if(p)
					return 0;
			}	
		}
	} //大while
	return 1;	//所有的都遍历完了,还没说明不是完全二叉树,那就是完全的呗
}

Question 7:
这个题若是画图题就不难,算法题有些抽象。
核心在于划分子树,这就要用到变量来划清界限,例如用前序确定根节点后,在中序划分为左子树——根——右子树,需要标记左子树的头和尾右子树的头和尾,这就需要4个整数变量。
l1,h1为先序的第一个和最后一个结点下标
l2,h2为中序的第一个和最后一个结点下标

BiTree PreInCreate(ElemType A[],ElemType B[],int l1,int h1,int l2,int h2){
	//传入表示边界的参数,为了往下递归
	//初始调用时,l1=l2=1; h1=h2=n;分别为整体的头和尾
	BiTree root=(BiTree)malloc(sizeof(BiTNode));	//动态申请一个根,每调用一次都会申请一个新结点,作为当前子树的根,不断递归。
	root->data=A[l1];		//先序定根

	int i,llen.rlen;		//定义循环计数 i , 左子树长度 llen,右子树长度 rlen
	for( i=l2;B[i]!=root->data;i++);	//中序定左右,从第一个开始直到找到根,这都是左子树
	//这个for循环是个空循环,只用来计数 i,当前 i 为根节点下标
	
	llen=i-l2;	//左子树长度,根节点下表减去当前序列中的第一个,以后还会在分,第一个结点可能就不是此时的l2了
	rlen=h2-i;	//右子树长度

	if(llen)			//左子树不空,就继续创建左子树,修改边界,为此时的左子树序列
		root->lchild=PreInCreate(A,B,l1+1,l1+llen,l2,l2_llen-1);
	else
		root->rchild=null;
		
		//边界参数怎么修改的?
		//l1+1为下一个根的下标;l1+llen由原来的h1变来,先序的最后一个。划分给了左子树多少结点,先序的最后一个就到哪。
		//l2没变,中序第一个结点还是第一个结点,l2+llen-1中序最后一个结点变了,
		//例如 初始时 l2=1,若左子树长度为1,l2+llen=2,而左子树只有1个就是1,位置对应应该是 l2+llen-1。前序为什么都后移一位,因为根节点已经被创建过了,中序为什么不后移,因为他的根在中间,中序数组中最左边的不是根;所以在边界变量上体现在先序比中序的总体要大1位。
		//继续代码
	if(rlen)
		root->rchild=PreInCreate(A,B,h1-rlen+1,h1,h2-rlen+1,h2);
	else
		root->rchild=null;
		
		//右子树都是从右边算的,最后往前减的(n-len),而不是1+len
		//h2-rlen是根的位置,已经创建完了,所以他的右边一位
		
	return root;
}

Question 8:
对于满二叉树,
前序:根——左——右
后续:左——右——根
1.左右子树结点数相等;
2.先序的第一个结点 = 后序的最后一个结点;
这就可以想到,把pre[]的最后一个结点赋给post[]的第一个结点,剩下的可分成左、右子树(从中间分),分别递归

void PreToPost(ElemType pre[],int l1,int h1,ElemType post[],int l2,int h2){
	int half;	//中间划分
	if(h1>=l1){	//说明这一段有结点
		post[h2]=pre[l1];	//后序序列的第一个点=前序最后一个点
		half=(h1-l1)/2;		//找到划分点
		PreToPost(pre,l1+1,h1+half,post,l2,l2+half-1);		//转换左子树
		PreToPost(pre,l1+half+1,h1,post,l2+half,h2-1);
	}
}
//递归完成后 post[]存的就是后序序列

Question 9:
任选树的遍历算法,修改visit函数(本来是访问功能,修改为计数,若度为2,则计数++)

typedef struct BiTNode{
	ElemType data;
	struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;

int num=0;		//全局变量
void Double_indegree(BiTree T){	//无返回值类型,用全局变量带回
	if(T){
		if(T->lchild&&T->rchild)
			num++;
		Double_indegree(T->lchild);
		Double_indegree(T->rchild);
	}
}

或者另一种写法有返回值
int Double_indegree(BiTree T){
	if(!T) return 0;
	if(T->lchild&&T->rchild)
		return 	Double_indegree(T->lchild)+Double_indegree(T->rchild)+1;
	else
		return 	Double_indegree(T->lchild)+Double_indegree(T->rchild);
}

Question 10:
自下而上交换,利用递归先从顶递归到最底部,交换。

void swap(BiTree &T){
	swap(T->lchild);
	swap(T->rchild);
	//进行左右递归到底,下面是交换
	BiTree temp=T->lchild;
	T->lchild=T->rchild;
	t->rchild=temp;
}

Question 11:
就进行先序遍历,每遍历一个结点就 计数++,到计数器=k时,返回data即可

int i=0;	//全局的计数器
int  Pre_k(BiTree T,int k){
	if(T==null) 
		return -1;	//表示查找失败
	if(i==k)
		return T->data;
	i++;
	int p;		//定义一个整数,临时存储一下结果
	p=Pre_k(T->lchild,k);	//左子树递归的返回值
	if(p!=-1)	//返回值若不是-1 则只可能为 T->data就是所需值直接返回
		return p;		
	p=Pre_k(T->rchild,k);	//左子树没找到,才会走到这一步,且无需判断
		return p;	//没在左,肯定在右!
		
	}
}

Question 12:
1.先找到x;2.删除并释放空间;这是两个基本操作,合并在一起。

void Delete(BiTree &T){	//删除操作
	if(T){
		Delete(T->lchild);
		Delete(T->rchild);
		free(T);
	}
}
void Search_Del(BiTree T,int x){
	if(T){
		if(T->data==x)
			Delete(T);                              
		Search(T->lchild,x);
		Search(T->rchild,x);
	}
}

非递归后序遍历,找到值为x的点后,输出栈中的元素即可

void Ancestor(BiTree T,int x){
	stack s;//假设已经定义好了
	top=0;
	BiTree p=T;
	while(p||top>0){
		if(p){
			top++;
			s[top].data=p;
			s[top].flag=0;
			p=p->lchild
		}
		
		while(top!=0&&s[top].flag==1) {	//修改visit
			if(p->data==x){
				for(int i=1;i<=top;i++)
					printf("%d",s[i].data->data);
			}
			top--;
		}	
			
		if(top!=0){
			s[top].flag=1;
			p=s[top].data->rchild;
		}
		
	}
}

Question 14:
前、中、后遍历都是对于叶子都是先左后右,任取一个遍历方法。
设置前驱结点指针pre,初始为空;
第一个叶子用指针head指向,遍历到叶子时,将其前驱的rchild指向他,最后一个叶子的rchild为空。

//采用中序,修改visit中的代码即可
LinkList head,pre=NULL;
LinkList InOrder(BiTree T){
	if(T){
		InOrder(T->lchild);
		//visit
		if(T->lchild==NULL&&T->rchild==NULL){
			if(pre==NULL){		//处理第一个叶子时单独操作
				head-=T;
				pre=T;	
			}
			else{
				pre->rchild=T;
				pre=T;	
			}	
		}
		InOrder(T->rchild);
		pre->rchild=NULL;	//表尾置空
	}
	return head;	//返回head就等于整个链表
}

Question 15:
递归思想求解,
若T1和T2都是空树,则相似;
若一个为空一个不空,则不相似;
否则递归比较他们的左、右子树是否相似。

bool similar(BiTree T1,BiTree T2){
	bool left,right;	//接收左右子树的返回值,方便比较是否相似
	if(T1==NULL&&T2==NULL)
		return true;
	else if(T1==NULL||T2==NULL)
		return false;
	else{
		left=similar(T1->lchild,T1->rchild);
		right=similar(T2->lchild,T2->rchild);
		return	left&&right;
	}
}

Question 16:
找关系,在后序遍历中,某结点的前驱是:
1.有右孩子,则前驱为右孩子;
2.无右孩子,有左孩子,则前驱为左孩子;
3.无左无右,比较复杂。设 f 是当前结点 p 的中序线索前驱,f的左孩子就是p的前驱,若f无左孩子,继续找其前驱是否有左孩子,直到有左孩子,那个左孩子就是p的后序前驱。
4.若p是中序遍历的第一个结点(左下角),也是后序的第一个,则无前驱

ThreadTree InPostPre(ThreadTree T,ThreadTree p){
//在线索二叉树T中,找到p的后序前驱,设为q
	ThreadTree q;
	if(p->rtag==0)		//情况1
		q=p->rchild;
	else if(p->ltag==0)		//情况2
		q=p->lchild;
	else if(p->lchild==NULL)		//情况4
		q=NULL;	
	else{				//情况3最复杂,代码多 ,写在最后多美观
		//顺着左线索找到p的祖先,
		//再找该祖先的左孩子
		while(p->ltag==1&&p->lchild!=NULL)	//有左线索。跳出循环只有两种情况:1.有左孩子了,ltag=0; 2.到头了,左线索为空,到第一个节点了;
			p=p->lchild;
			
		if(p->ltag==0)		//跳出循环后,判断是哪种情况,有左孩子,则左子是前驱
				q=p->lchild;	
		else					//只能是第二种情况,即为第一个结点了,无前驱
				q=NULL;
	}
	return q;
}

Question 17:
二叉树的带权路径长度为每个叶子的深度与权值乘积总和
利用static 变量记录wpl

int wpl_pre(BiTree T,int deep){
	static int wpl=0;			//存储总和
	if(T->lchild==NULL&&T->rchild==NULL)	//若为叶子节点,则积累wpl。
		wpl=wpl+deep*T->weight;		//weight属性在定义结构体时给出,就是data
	if(T->lchild)
		wpl_pre(T,deep+1);
	if(T->rchild)
		wpl_pre(T,deep+1);
	return wpl;
}
int WPL(BiTree T){
	return wpl_pre(T,0);
}

Question 18:
基于中序遍历,得到所需表达式;
除了根结点和叶子结点,遍历到其他结点时在其左子树之前加" ( ",遍历完右子树之后加上 " ) "。

void BiTreeToExp(BiTree T,int deep){
	if(T==NULL) return;		//1.空树
	else if(T->lchild==NULL&&T->rchild==NULL)	//若为叶子结点
		printf("%s",T->data);		//直接输出数,而不要加括号
	else{			//分支节点(单、双分支)情况
		if(deep>1)
			printf("(");		//deep>1,表示不是根节点,在遍历左子树之前,需要加(
			
		BiTreeToExp(T->lchild,deep+1);	//左子树
		
		printf("%s",T->data);	//输出操作符	//输出当前结点
		
		BiTreeToExp(T->rchild,deep+1);
		
		if(deep>1)		//遍历完右子树,加上右括号
			printf(")");
	}
}

void Print(BiTree T){
	BiTreeToExp(T,1);	//输出函数。调用该算法
}

明确叶子节点满足什么条件:
若结点没有孩子,则比为叶子。即在孩子兄弟表示法中,firstchild为空就没孩子。
所有的叶子就是 孩子子树的叶子加上兄弟子树的叶子,(即二叉树的左右子树)

typedef struct node{
	ElemType data;
	struct node *firstchild,*sibling;
}*Tree;
int Leaves(Tree T){
	if(T==NULL) return 0;
	if(T->firstchild==NULL)		//无孩子
		return 1+Leaves(T->sibling);	//该节点为叶子,计数+1,再加节点右兄弟们的叶子一起返回。
	else
		return Leaves(T->firstchild)+Leaves(T->sibling);
}

若树为空,则高度为0;
否则高度为第一个孩子的高度+1兄弟子树高度 的大者;
类比二叉树的高度,左子树和右子树高度的大者,这里存储时,我的右兄弟变成了我的右孩子,比我多了一层。所有我要+1 再与你比较,取大者。

int Height(CSTree bt){
	int height_c,height_s;	//分别表示第一孩子的高度,和兄弟的高度
	if(bt==NULL) return 0;
	else{
		height_c=Height(bt->firstchild);	//第一个孩子的高度
		height_s=Height(bt->sibling);		//右兄弟的高度
		if(height_c+1>height_s)
			return height_c+1;	//每次返回的都是当前这个结点的最大高度,这个点可能是孩子可能是兄弟
		else
			return height_s;
	}
}

与层次序列有关,设立一个数组,pointer[]用来存储新建树的各结点地址。
再根据层次序列与每个结点的度,逐个链接。

void ceateCSTree(CSTree &T,DataType e[],int degree[],int n){
//参数需要 层次序列 e[],各节点的度degree[],结点个数n
	CSNode *pointer=new CSNode[maxsize];//申请动态数组
	int i,j,d,k=0;
	for(i=0;i<n;i++){	//pointer全部初始化为指针为空,只保存data,表示孤立的各节点。
		pointer[i]->data=e[i];	
		pointer[i]->lchild=pointer[i]->rsibling=NULL;		
	}
	for(i=0;i<n;i++){	//每一个节点都链接其左儿子和右兄弟
		d=degree[i];	//d暂存当前结点的度,
		if(d){		
			k++;	//k为左儿子的编号,因为初始k=0,为根,他的左儿子就是k=1,没错,当i=2时,k怎么等于左儿子编号的?
			pointer[i]->lchild=pointer[k];	//连左孩子
			
			//d=1时不执行下面的循环,只连左儿子,没有右兄弟
			for(j=2;j<=d;j++){
				k++;		//循环执行完毕后k=d,即为最右边的兄弟;当下一次大循环i=2时,k++,就变成了下一行的第一个结点,即左孩子编号。
				pointer[k-1]->rsiblng=pointer[k];	//左兄弟连右兄弟
			}	
		}
		T=pointer[0];
		delete [] pointer;
	}
}

二叉排序树,中序遍历为有序序列:利用中序遍历,后一个元素一定比前一个元素大。

int pre=-1;	//全局变量,保存当前结点的前一个结点的值
int IsBST(BiTree T){
	int b1,b2;
	if(T==NULL)	//空树
		return 1;	//也算
	else{
		b1=IsBST(T->lchild);
		
		//visit(),中序遍历,修改visit函数,把访问变成判断
		if(b1==0||pre>=T->data)	//失败的条件,1.左子树已经不是了;2.当前点不是
			return 0;
			
		pre=T->data;	//若没进入上面的if,则意味着当前结点符合排序规则,pre记住当前结点,比较下一结点。
		

		b2=IsBST(T->rchild);
	}
}
查找
int Search(BSTree T,int key){\
	while(T||key!=T->data){
		if(key<T->data)
			T=T->lchild;
		else
			T=T->rchild;
	}
	return T;
}

插入
int Insert(BSTree T,int key){
	if(T==NULL){		//情况1:找到空地位置,要插入的位置,进行插入
		BSTree p=(BSTree)malloc(sizeof(BSTree));
		p->data=keyl
		p->lchild=p->rchild=NULL;	
		return 1; //找到空地,插入完成
	}
	else if(T->data==key)		//情况2
		return 0;		//有相同的元素,插入失败
	else if(key<T->data)		//情况3:元素应插入其左子树上
		return Insert(T->lchild);
	else				//情况4:应插入在右子树上
		return Insert(T->rchild);
}

构造:循环调用插入算法,即可
for(int i=0;i<n;i++){
	Insert(T,str[i]);
}

Question 24:
首先明确顺序:从大到小,即右——根——左方式遍历
然后按这个方法进行遍历输出就行了;代码我都懒得写(中序递归算法的左右子树递归交换一下位置)

Question 25:

count为结点的一个属性,表示子树有多少个结点(包括自己)
BSTNode *Search_k(BSTree T,int k,int n){
	if(k<1||k>T->count)	return NULL;	//k非法,小于1,大于节点个数
	if(T->lchild==NULL){		//如果没有左子树。1.k在根;2.k在右子树上
		if(k==1) return T;		
		else return Search_k(T->rchild,k-1);	//往右子树中找 应该是k-1小的
	}
	else{		//存在左子树,看看左子树有多少个结点
		if(T->lchild->count==k-1)	//左子树有k-1个结点,第k个就是根
			return T;	
		else if(T->lchild->count>k-1)  //左子树的结点超级多,k一定在左子树上
			return Search_k(T->lchild,k);
		else
			return Search_k(T->rchild,k-(T->lchild->count+1));
	}
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值