求二叉树中两个节点的最低公共祖先

1、该树是一棵二叉搜索树
在二叉搜索树中,左子树的所有结点的值一定比根结点小,右子树中的所有结点的值一定比根结点大。根据二叉树的这个性质,我们只需要从根结点开始与两个输入结点的值进行比较,如果当前结点的值比输入的两个结点的值都大,那么最低的公共祖先一定在左子树中,然后继续遍历左子树;如果当前结点的值比输入的两个结点的值都小,那么最低的公共祖先一定在右子树中,然后继续遍历右子树。如果当前结点的值在两个输入结点的值之间那么该结点就是最低的公共祖先。
具体代码:

//结点结构
template<typename V>
struct BinarySearchTreeNode
{
    BinarySearchTreeNode(const V& val)
    : _Left(NULL)
    , _Right(NULL)
    , _Parent(NULL)
    , _val(val)
    {}
    BinarySearchTreeNode<V>* _Left;
    BinarySearchTreeNode<V>* _Right;
    BinarySearchTreeNode<V>* _Parent;
    V _val;
};
//寻找最低公共祖先
BinarySearchTreeNode<V>* _PublicAncestor(BinarySearchTreeNode<V>* pRoot, BinarySearchTreeNode<V>* Node1, BinarySearchTreeNode<V>* Node2)
{
    if (pRoot == NULL || Node1 == NULL || Node2 == NULL)
        return NULL;
    BinarySearchTreeNode<V>* pCur = pRoot;
    while (pCur)
    {
        if (pCur->_val > Node1->_val&& pCur->_val> Node2->_val)
            pCur = pCur->_Left;
        else if (pCur->_val< Node1->_val&& pCur->_val< Node2->_val)
            pCur = pCur->_Right;
        else
            return pCur;
    }
    return NULL;
}

2、该树是一棵有父指针的二叉树
一棵具有父指针的树,那么该树的叶子节点到根结点是一个由_pParent指针链起来的链表。输入两个结点,那么这两个结点位于两条链上,这两个结点的最低公共祖先就是这两条链的第一个公共结点。那么求两个结点的最低公共祖先问题就转换成求两个链表的第一个公共结点问题。
具体代码实现:

//链表结点结构
typedef struct Node
{
    int data;
    struct Node* next;
}Node,*PNode;
//求链表长度
int SizeOfList(PNode pHead)
{
    int count=0;
    if(pHead==NULL)
        return 0;
    while(pHead)
    {
        count++;
        pHead=pHead->next;
    }
    return count;
}
//获取两个链表的第一个公共结点
PNode GetFirstPublicNode(PNode pHead1,PNode pHead2)
{
    PNode pL1=pHead1;
    PNode pL2=pHead2;
    int size=0;
    int size1=0;
    int size2=0;
    if(pL1==NULL || pL2==NULL)
    {
        return NULL;
    }
    size1=SizeOfList(pHead1);//求链表长度
    size2=SizeOfList(pHead2);
    size=size1-size2;
    if(size>0)
    {
        while(size--)
        {
            pL1=pL1->next;  
        }
        pL1=pL1->next;
        pL2=pL2->next;
        if(pL1==pL2)
        {
            return pL1;
        }
    }
    else
    {
        size=0-size;
        while(size--)
        {
            pL2=pL2->next;
        }
        pL1=pL1->next;
        pL2=pL2->next;      
        if(pL1==pL2)
        {
            return pL1;
        }
    }
    return NULL;
}

3、该树是一棵普通的树
对于一棵普通的树,常规的解法就是从根结点开始遍历,每遍历到一个结点的时候就判断两个输入的结点是否在它的子树中,如果在,则继续再遍历它的所有子节点,这样一直向下遍历,直到找到最低祖先为止。但是这样的解法会使得一个结点重复被遍历多次,效率太低了。
但是我们可以这样做:可以先保存该树的根结点到输入的两个结点的路径至栈中,然后再寻找最低公共祖先。
具体实现:

//找结点路径
bool FindPath(BinaryTreeNode<T>* pRoot, BinaryTreeNode<T>* Node, stack<BinaryTreeNode<T>*> &s)
{
    if (pRoot == NULL || Node == NULL)
        return false;
    s.push(pRoot);
    if (pRoot == Node)
        return true;
    bool left = FindPath(pRoot->_pLeftChild ,Node, s);
    bool right = FindPath(pRoot->_pRightChild, Node, s);
    if (left == false && right == false) //左右子树都没有找到这个节点,说明此时这个节点不在路径当中,弹出。
    {
        s.pop();
        return false;
    }
    return true;
}
//最低公共祖先结点
BinaryTreeNode<T>* _LowestPublicAncestor(BinaryTreeNode<T>* pRoot, BinaryTreeNode<T>* Node1, BinaryTreeNode<T>* Node2)
{
    stack<BinaryTreeNode<T>*> s1;//保存路径
    stack<BinaryTreeNode<T>*> s2;
    FindPath(pRoot, Node1, s1);
    FindPath(pRoot, Node2, s2);
    int step = s1.size() - s2.size();
    if (step > 0)
    {
        while (step--)
            s1.pop();
    }
    else
    {
        step = -step;
        while (step--)
        {
            s2.pop();
        }
    }
    while (!s1.empty() && !s2.empty() && s1.top() != s2.top())
    {
        s1.pop();
        s2.pop();
    }
    return s1.top();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值