08 二叉树的下一个节点
题目描述:
给定一个二叉树和其中的一个节点,请找出中序遍历顺序的下一个节点并且返回。注意,树中的节点不仅包含左右子节点(指向左右子节点的指针),同时包含指向父节点的指针。
测试用例:
1)普通二叉树(完全二叉树、不完全二叉树)
2)特殊二叉树(所有节点都没有右/左子节点的二叉树,只有一个节点的二叉树,空树:根节点指针为nullptr)
3)不同位置的节点的下一个节点(下一个节点为当前节点的右子节点、右子树的最左节点、父节点、跨层的父节点;当前节点没有下一个节点)
解题思路:
建议:在解题时,画出具体的二叉树结构图、通过具体的例子找出中序遍历下一个节点的规律,设计可行的方法。

分三种情况讨论:
1)如果一个节点有右子树,那么它的下一个节点就是它的右子树的最左节点。即从右子节点出发一直沿着左子节点的指针寻找。如图中b(h)与a(f)。
2)该节点没有右子树,且该节点是其父节点的左节点,下一个节点是它的父节点。
3)该节点没有右子树,且该节点是其父节点的右节点时:可以沿着指向父节点的指针一直向上遍历,直到找到一个是它父节点的左子节点的节点。如果这样的节点存在,那么这个节点的父节点就是要找的下一个节点
4)初始化要找的下一个节点时,设为空指针。没有找到时,直接返回该空指针。
代码:
1)
/*
struct TreeLinkNode {
int val;
struct TreeLinkNode *left; //此处的struct对调用有影响么?没有
struct TreeLinkNode *right;
struct TreeLinkNode *next;
TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
}
};
*/
class Solution {
public:
//pNode: 给定的节点 不要修改其值
TreeLinkNode* GetNext(TreeLinkNode* pNode)
{
if( pNode == NULL ) //nullptr
return NULL;
//TreeLinkNode* nextNode = NULL ;
TreeLinkNode* nextNode = nullptr ;
//TreeLinkNode* nextNode = new TreeLinkNode();
if (pNode->right != NULL){
//error : 右子树非空,右子树的root节点则是指定节点pNode中序的下一个节点。
//nextNode = pNode->right;
//右子树非空,右子树的最左节点则是指定节点pNode中序的下一个节点。
TreeLinkNode* rightTree = pNode->right ;
while(rightTree->left!=NULL){
rightTree = rightTree->left ;
}
//把找到的左节点赋给返回值
nextNode = rightTree;
}else if (pNode->next!= nullptr){ //父节点非空--根节点没有父节点
//右子树为空时,根据父节点判断指定节点pNode是左子树还是右子树
if(pNode == pNode->next->left){
//是左节点,则在中序遍历中父节点是该节点的下一个节点
nextNode = pNode->next ;
}else{
//是右节点
//父节点是左节点,取父节点的父节点。父节点是右节点,对父节点的父节点重新判断。。。
//一直找到父节点是左节点的节点。
TreeLinkNode* parantNode = pNode->next ;
TreeLinkNode* currentNode = pNode ;
while(parantNode!=nullptr && currentNode == parantNode->right){
currentNode = parantNode;
parantNode = parantNode->next ;
}
nextNode = currentNode->next ;
}
}
return nextNode;
}
};
注意:
「1」注意中英文字符
「2」line22-28,当右子树非空时,下一个节点应该时右子树的最左节点,而不是根节点。
「3」line32一定要判断父节点非空才可以使用父节点 ->next,因为并不是所有的节点都有父节点,如树的根节点。
「4」在程序运行中,不要修改输入参数pNode,创建新的变量。如 currentNode 、parantNode 等。
2)思路同上面是一致的,只是在第三种情况时,代码更简洁。
/*
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 == nullptr){
return nullptr;
}
TreeLinkNode* next = nullptr;
//先右子节点的左子节点遍历
if(pNode->right != nullptr){
TreeLinkNode* rightNode = pNode->right;
while(rightNode->left != nullptr){
rightNode = rightNode->left;
}
next = rightNode;
}
//向父结点遍历
else if(pNode->next != nullptr){ //一定要判断父节点是否非空
TreeLinkNode* parentNode = pNode->next;
TreeLinkNode* currentNode = pNode;
//当前节点是左节点时,不进入while循环。右节点进入循环
//一定要判断父节点是否非空
while(parentNode != nullptr && currentNode == parentNode->right){
currentNode = parentNode;
parentNode = parentNode->next;
}
next = parentNode;
}
return next;
}
};
基础知识:
[1] NULL是0,nullptr是空指针void
https://blog.csdn.net/jays_/article/details/82586699
[2] 对变量的命名,要有意义。如父节点 parentNode,不要随便写pp、pc这种名字。

浙公网安备 33010602011771号