题意:问大小为n的二叉树的前序遍历的第k个节点是什么。
解法:根据k来进行DFS,因为k就是这个节点在中序遍历中的下标,那么很好找这个结点v。
假如找到一个结点i,如果i的左子树的节点数为l(l<k),那么由于中序遍历的特性,结点v肯定在i的右子树中,不然就在左子树中,就这样DFS
就可以找到节点V了,现在要的就是如何计算左子树的节点数l了。加入现在DFS到i的时候,这个树有n个节点,那么先不要管最后一层,因为最后
一层可以能不满,那么除去了最后一层后有p个节点(while(p*2<=n) p*=2;)。那么p/2,就分为了两部分,又因为这个p是算多了一个节点的,
所以p/2-1,那么这就是不管最后一层,i的左子树的结点的个数。至于为什么-1,可以画个二叉树来看看,一个3层的满二叉树的节点数是7个的。
但是三层的时候p=8,分成了两部分后,左右子树多了一个节点,那么就要减去一个。那么现在还要加上最后一层的情况,如果最后一层满的情况
那么最后一层应该有p个节点,分为两部分就是p/2,如果最后一层左边满的话,左边也是p/2。如果左边也不满的话就是n-(p-1)个,这里的减1和
上面-1解释一样,既(p-1)为上面满的节点数。所以得出了i的左子树个数l=p/2-1+min(p/2,(n-(p-1));这里的min用于判断最后一层的左边满不满。
解法:根据k来进行DFS,因为k就是这个节点在中序遍历中的下标,那么很好找这个结点v。
假如找到一个结点i,如果i的左子树的节点数为l(l<k),那么由于中序遍历的特性,结点v肯定在i的右子树中,不然就在左子树中,就这样DFS
就可以找到节点V了,现在要的就是如何计算左子树的节点数l了。加入现在DFS到i的时候,这个树有n个节点,那么先不要管最后一层,因为最后
一层可以能不满,那么除去了最后一层后有p个节点(while(p*2<=n) p*=2;)。那么p/2,就分为了两部分,又因为这个p是算多了一个节点的,
所以p/2-1,那么这就是不管最后一层,i的左子树的结点的个数。至于为什么-1,可以画个二叉树来看看,一个3层的满二叉树的节点数是7个的。
但是三层的时候p=8,分成了两部分后,左右子树多了一个节点,那么就要减去一个。那么现在还要加上最后一层的情况,如果最后一层满的情况
那么最后一层应该有p个节点,分为两部分就是p/2,如果最后一层左边满的话,左边也是p/2。如果左边也不满的话就是n-(p-1)个,这里的减1和
上面-1解释一样,既(p-1)为上面满的节点数。所以得出了i的左子树个数l=p/2-1+min(p/2,(n-(p-1));这里的min用于判断最后一层的左边满不满。
代码如下:
#include<bits/stdc++.h>
using namespace std;
int dfs(int v,int n,int k)
{
int p=1;
while(p*2<=n)
p*=2;
int l=p/2-1+min(n-(p-1),p/2);
printf("%d %d\n",p,n);
if((n==1)||(k==l+1))
return v;
return l<=k?dfs(2*v+1,n-l-1,k-l-1):dfs(2*v,l,k);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,k;
scanf("%d %d",&n,&k);
printf("%d\n",dfs(1,n,k));
}
}