二叉搜索树节点的前驱后继节点
之前写过文章介绍了二叉搜索树以及其上的基本操作,但不包括求节点的前驱结点和后继节点。
这是一个很老的问题了,首先看下某节点前驱和后继节点的定义。一个节点的
前驱结点:节点val值小于该节点val值并且值最大的节点
后继节点:节点val值大于该节点val值并且值最小的节点
算法导论中给出了详细的求前驱结点和后继节点的算法,但是其中的节点数据结构包含了指向父亲节点的指针,但是一般的给出的节点不包含父亲指针,这就加大了就前驱节点和后继节点的难度。
本文在不含父指针的节点数据结构下,分析给出了时间复杂度为O(lgN)的求前驱后继结点的算法。
例子
树节点的依旧定义如下(我们的基本树节点没有指向父节点的指针):
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
给出一个二叉树如下图:
二叉树的节点val值是按照二叉树中序遍历顺序连续设定。
前驱结点
- 如图4的前驱结点是3
- 2的前驱结点是1
- 6的前驱结点是5
后继节点
- 7的后继结点是8
- 5的后继节点是6
- 2的后继节点是3
规则
根据上述例子,我们可以得到下述规则:
前驱节点
- 若一个节点有左子树,那么该节点的前驱节点是其左子树中val值最大的节点(也就是左子树中所谓的rightMostNode)
- 若一个节点没有左子树,那么判断该节点和其父节点的关系
2.1 若该节点是其父节点的右边孩子,那么该节点的前驱结点即为其父节点。
2.2 若该节点是其父节点的左边孩子,那么需要沿着其父亲节点一直向树的顶端寻找,直到找到一个节点P,P节点是其父节点Q的右边孩子(可参考例子2的前驱结点是1),那么Q就是该节点的后继节点
类似,我么可以得到求后继节点的规则。
后继节点
- 若一个节点有右子树,那么该节点的后继节点是其右子树中val值最小的节点(也就是右子树中所谓的leftMostNode)
- 若一个节点没有右子树,那么判断该节点和其父节点的关系
2.1 若该节点是其父节点的左边孩子,那么该节点的后继结点即为其父节点
2.2 若该节点是其父节点的右边孩子,那么需要沿着其父亲节点一直向树的顶端寻找,直到找到一个节点P,P节点是其父节点Q的左边孩子(可参考例子2的前驱结点是1),那么Q就是该节点的后继节点
实现
求前驱节点
规则中我们是从下往上找,但实际代码中是