二叉查找树(6) - 最近公共祖先LCA

目录

1.LCA介绍

2.LCA定义

3.代码实现


1.LCA介绍

给定二叉查找树中的两个节点,求它们的最近公共祖先(Lowest Common Ancestor - LCA)。

在详细介绍之前,可以先参考下这篇文章《二叉树(70) - 最近公共祖先》。

函数原型定义如下:

Node *getLCA(Node* root, int n1, int n2)    //其中n1和n2是指定的两个节点值

例如:上述BST中,10和14的LCA是12,而8和14的LCA是8。

2.LCA定义

下面是来自Wikipedia的关于LCA的定义:

假设存在一颗二叉树T,其中节点n1和n2的最小共同祖先的定义为,T中最小的节点,它包含了n1和n2做为后代(同时规定一个节点自己可以做为自己的后代)。

节点n1和n2的LCA是一个共同的祖先,距离root根节点最远。对于LCA进行计算是很有用的,例如,可以计算树中一对节点之间的距离:n1到n2的距离为n1到root的距离,加上n2的root的距离,再减去它们的LCA到root距离的两倍。

3.代码实现

可以利用BST的特性。从root节点开始进行递归遍历。此方法的主要思路是,当从top遍历至buttom时,第一次遇到的节点n,且n满足n1<n<n2,或者n等于n1或n2,则n是n1和n2的LCA。安装这种方法递归的遍历,当节点值比n1和n2都大时,则LCA位于此节点的左子树中;如果节点值小于n1和n2,则LCA位于此节点的右子树中。否则root就是LCA。

// C++程序,求BST中两个节点的LCA
#include <iostream>

struct Node {
    int key;
    Node* left;
    Node* right;
};

//求n1和n2的LCA。假设n1和n2都位于BST中。
Node* getLCA(Node* root, int n1, int n2) {
    if (root == NULL)
        return NULL;

    // 如果n1和n2小于root,则LCA位于左子树中
    if (root->key > n1 && root->key > n2)
        return getLCA(root->left, n1, n2);

    // 如果n1和n2大于root,则LCA位于右子树中
    if (root->key < n1 && root->key < n2)
        return getLCA(root->right, n1, n2);

    return root;
}

// 创建一个新的BST节点
Node* createNewNode(int item) {
    Node* temp = new Node;
    temp->key = item;
    temp->left = temp->right = NULL;
    return temp;
}

int main() {
    /*
         20
        /  \
      8   22
     / \
    4   12
       /  \
     10   14
    */
    Node* root = createNewNode(20);
    root->left = createNewNode(8);
    root->right = createNewNode(22);
    root->left->left = createNewNode(4);
    root->left->right = createNewNode(12);
    root->left->right->left = createNewNode(10);
    root->left->right->right = createNewNode(14);

    int n1 = 10, n2 = 14;
    Node* t = getLCA(root, n1, n2);
    printf("LCA of %d and %d is %d \n", n1, n2, t->key);

    n1 = 14, n2 = 8;
    t = getLCA(root, n1, n2);
    printf("LCA of %d and %d is %d \n", n1, n2, t->key);

    n1 = 10, n2 = 22;
    t = getLCA(root, n1, n2);
    printf("LCA of %d and %d is %d \n", n1, n2, t->key);

    return 0;
}

运行结果:
LCA of 10 and 14 is 12
LCA of 14 and 8 is 8
LCA of 10 and 22 is 20

时间复杂度: O(h),其中h是树的高度。

另外,上面程序还需要额外的内存来进行递归的函数调用栈。可以使用下面的遍历方法来避免额外的内存空间。

//求节点n1和n2的LCA
Node* getLCA(Node* root, int n1, int n2) {
    while (root != NULL) {
        // 如果n1和n2小于root,则LCA位于左子树中
        if (root->data > n1 && root->data > n2)
            root = root->left;
        // 如果n1和n2大于root,则LCA位于右子树中
        else if (root->data < n1 && root->data < n2)
            root = root->right;
        else 
            break;
    }
    return root;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值