法1、暴力法:这道题我们拿到后,先想最简单的解决办法就是把整棵树按中序遍历一遍,然后就可以找到下一个节点了,但这种方法肯定时间空间开销都很大
法2、这类题说白了就是找规律,一棵树中什么样的节点会是它在中序的下一个节点,我们先动手画一棵节点不要太少的二叉树,然后一个节点一个节点看,用我们的人脑思考它的下一个节点是怎么找到的,最后找到的规律如下
站在所给节点的视角:
1、如果右儿子非空,则下一个节点就是右儿子的最左子孙
2、如果右儿子为空,则回溯至第一个作为“左儿子”的祖先节点处,它的父亲节点就是我们要找的节点
3、如果回溯至根节点还没找到满足步骤2的节点,那么所给节点的下一个节点不存在
接下来只需要把这个过程代码化即可。
/找到给定节点中序遍历的下一个节点
#include <stdio.h>
struct Node{
int data;
Node* left;
Node* right;
Node* father;
};
Node* findNext(Node* now){
if(now==NULL) //如果传来的结点是空则直接返回空
return NULL;
if(now->right!=NULL){ //如果右儿子非空,则下一个节点就是右儿子的最左儿子
Node* p = now->right;
while(p->left!=NULL){
p = p->left;
}
return p;
}
Node* p = now; //否则,下一个节点就是作为第一个左儿子的祖先的父亲
while(p->father!=NULL && p!=p->father->left ){ //回溯至第一个祖先中第一个左儿子 ,它的父亲就是我们要找的节点
p = p->father;
}
return p->father;
}
void create(Node*& T){ //根据带空指针信息的先序序列创建树
int x;
scanf("%d",&x);
if(x==0)
return ;
T = new Node;
T->data = x;
T->left = T->right = NULL;
create(T->left);
create(T->right);
}
void setFather(Node* T){ //给树里的结点设置父指针,这里没对根节点的父指针赋值,而是在调用之前手动设置根节点父指针为空
if(T == NULL)
return;
if(T->left!=NULL)
T->left->father = T;
if(T->right != NULL)
T->right->father = T;
setFather(T->left);
setFather(T->right);
}
void midOrder(Node* T){ //中序遍历
if(T==NULL)
return;
midOrder(T->left);
printf("%d ",T->data);
midOrder(T->right);
}
int main(){
Node * root = NULL;
printf("请输入:\n");
create(root);
setFather(root);
root->father = NULL;
printf("中序遍历:\n");
midOrder(root);
printf("\n"); //这里用1 5 8 0 0 0 6 0 0 做测试
printf("1的下一个是%d\n",findNext(root)->data);
printf("5的下一个是%d\n",findNext(root->left)->data);
printf("8的下一个是%d\n",findNext(root->left->left)->data);
if( findNext(root->right) == NULL)
printf("6的下一个是空\n");
if(findNext(NULL) == NULL)
printf("0的下一个是空\n");
return 0;
}