题目:给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
思路:通过多次画图可以总结出来普遍的数学规律。假如我们要找结点b的中序遍历的下一个结点。根据中序遍历的特点,先访问b的左子树,然后访问结点b,最后访问b的右子树。
我们可以发现问题的关键在于b是否有右子树。
如上图所示:
1、如果结点b有右子树。那么结点b的下一个结点一定出现在其右子树的部分。具体在右子树的最左子树的那个结点。也就是m结点。
2、如果结点b无右子树。那么结点b的下一个结点会出现在回溯的路上。具体来说
- 2.1 如果结点b是父亲结点的左孩子,那么b的下一个结点就是其父亲结点。也就是a
- 2.2 如果结点b是父亲结点的右孩子,那么b的下一个结点应该是结点r。结点r是从b的父亲结点开始向上回溯,一旦出现左分支,就发现r了。
代码如下
/*
struct TreeLinkNode {
int val;
struct TreeLinkNode *left;
struct TreeLinkNode *right;
struct TreeLinkNode *next;
TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
}
};
*/
class Solution {
public:
TreeLinkNode* GetNext(TreeLinkNode* pNode) {
if(pNode == NULL){
return NULL;
}
//
if(pNode->right != NULL){
//有 右子树,那么下一个结点就是右子树的最左子树
return FindLChild(pNode->right);
}else{
//没有 右子树
if(pNode->next == NULL){
return NULL;
}else{
if(pNode->next->left == pNode){
//左子树,返回父亲结点即可
return pNode->next;
}else{
return FindRL_root(pNode->next);
}
}
}
}
TreeLinkNode* FindRL_root(TreeLinkNode* node){
if(node == NULL){
return NULL;
}
TreeLinkNode* father = node->next;
while(father!=NULL){
if(father->right == node){
//继续循环
node = father;
father = father->next;
}else if(father->left == node){
return father;
}
}
return father;
}
TreeLinkNode* FindLChild(TreeLinkNode* node){
//找到该结点的最左子树,如果没有返回其本身即可
while(node->left != NULL){
node = node->left;
}
return node;
}
};