题目
设计一个算法,找出二叉查找树中指定节点的“下一个节点”(也就是中序后继)。可以假定每个节点都含有指向父节点的链接。
分析
既然是二叉查找树,我们知道中序遍历结果为递增有序,那么可以直接得到中序遍历结果,在线性查找指定节点的后继。 上述方法是普通解法,但是我们看到题目说每个节点有父节点指针,那么我们可以换一个思路: (1)假设该节点有右子树,那么根据中序遍历的步骤,下一个访问节点即是其右子树的最左节点; (2)假设该节点没有右子树,其在父节点的左子树上,那么下一个访问节点即是其父节点; (3)假设该节点没有右子树,且其在父节点的右子树上,这怎么办呢?我们依次根据其父节点指针上溯,直到找到一个祖先节点,使得该节点位于此祖先节点的左子树。 其中,后两种情况可以合二为一处理。
代码
/*方法一,得到中序遍历序列*/
int findSucc(TreeNode* root, int p) {
// write code here
vector<int> inOrderVals;
inOrder(inOrderVals, root);
auto iter = find(inOrderVals.begin(), inOrderVals.end(), p);
if (++iter != inOrderVals.end())
return *iter;
return -1;
}
/*中序遍历二叉树*/
void inOrder(vector<int> &vals, TreeNode *root)
{
if (!root)
return;
inOrder(vals, root->left);
vals.push_back(root->val);
inOrder(vals, root->right);
}
/*方法二:假设该树每个节点含有指向父节点的链接*/
TreeNode* FindSucc2(TreeNode *root, TreeNode *node)
{
if (root == NULL || node == NULL)
return NULL;
/*如果该节点有右子树,则右子树的最左边节点即为后继*/
if (node->right != NULL)
{
TreeNode *ret = node->right;
while (ret->left != NULL)
ret = ret->left;
return ret;
}
else {
/*若该节点无右子树,上溯遍历,找到第一个祖先节点使得该节点位于其左子树*/
TreeNode *p = node->parent;
while (p != NULL && node == p->right)
{
node = p;
p = p->parent;
}
return node;
}
}