从二叉树中找出那难以捉摸的共同祖先
2023-12-15 12:50:09
在浩瀚的数据森林中,二叉搜索树是一棵枝繁叶茂的巨木,它的独特之处在于,每个节点的值都比它的左子树的所有值大,比它的右子树的所有值小,就好比一座数字金字塔,井然有序。而在二叉搜索树中,找到两个节点的最近公共祖先,就好比在错综复杂的树干中寻找共同的根源。今天,我们就来揭开这层迷雾,用清晰的思路和简洁的算法,找出二叉搜索树中的共同祖先。
算法演练
首先,我们先来定义一个二叉搜索树节点的结构:
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
现在,我们开始探索算法。我们的目标是找到二叉搜索树中两个节点p和q的最近公共祖先。为此,我们可以采用递归的方法,从根节点开始,沿途判断p和q与当前节点的关系,从而缩小搜索范围。
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == NULL || p == NULL || q == NULL) {
return NULL;
}
if (root->val > p->val && root->val > q->val) {
return lowestCommonAncestor(root->left, p, q);
}
if (root->val < p->val && root->val < q->val) {
return lowestCommonAncestor(root->right, p, q);
}
return root;
}
算法剖析
在这个递归算法中,我们首先判断根节点是否为空,或者p和q是否为空。如果任一条件成立,我们直接返回NULL,因为不存在最近公共祖先。
接下来,我们根据根节点的值和p、q的值进行比较,判断p和q是位于根节点的左子树还是右子树。如果p和q都在根节点的左子树,那么它们的最近公共祖先一定在左子树中,因此我们调用函数 lowestCommonAncestor(root->left, p, q)
继续搜索。
同理,如果p和q都在根节点的右子树,那么它们的最近公共祖先一定在右子树中,因此我们调用函数 lowestCommonAncestor(root->right, p, q)
继续搜索。
最有趣的情况是,当p和q分别位于根节点的左右子树时,这时它们的最近公共祖先就是根节点本身。因此,我们返回根节点作为它们的最近公共祖先。
示例演示
让我们用一个实际的二叉搜索树来演示一下这个算法。假设我们有如下二叉搜索树:
50
/ \
30 70
/ \ / \
20 40 60 80
现在,我们想找到节点20和节点80的最近公共祖先。
第一步,我们从根节点50开始,比较50、20和80的值。50比20和80都大,所以20和80一定在50的左子树或右子树中。
第二步,我们比较50和30的值。50比30大,所以20和80一定在30的左子树或右子树中。
第三步,我们比较30和20的值。30比20大,所以20一定在30的左子树中。
第四步,我们找到了20,它就是20和80的最近公共祖先。
总结
这就是我们找到二叉搜索树中两个节点最近公共祖先的算法。通过递归的方法,我们层层深入,不断缩小搜索范围,最终找到了这两个节点的共同根源。下次当你面对一个二叉搜索树时,别再为寻找最近公共祖先而烦恼,用这个算法,你将轻而易举地找到答案。