返回

从二叉树中找出那难以捉摸的共同祖先

闲谈

在浩瀚的数据森林中,二叉搜索树是一棵枝繁叶茂的巨木,它的独特之处在于,每个节点的值都比它的左子树的所有值大,比它的右子树的所有值小,就好比一座数字金字塔,井然有序。而在二叉搜索树中,找到两个节点的最近公共祖先,就好比在错综复杂的树干中寻找共同的根源。今天,我们就来揭开这层迷雾,用清晰的思路和简洁的算法,找出二叉搜索树中的共同祖先。

算法演练
首先,我们先来定义一个二叉搜索树节点的结构:

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的最近公共祖先。

总结
这就是我们找到二叉搜索树中两个节点最近公共祖先的算法。通过递归的方法,我们层层深入,不断缩小搜索范围,最终找到了这两个节点的共同根源。下次当你面对一个二叉搜索树时,别再为寻找最近公共祖先而烦恼,用这个算法,你将轻而易举地找到答案。