学习笔记——二叉树两结点的最低共同父结点

2013.10.8 上午八点半

问题:二叉树两结点的最低共同父结点

问题描述:

二叉树的结点定义如下:

 

struct TreeNode

{

   int m_nvalue;

   TreeNode* m_pLeft;

   TreeNode* m_pRight;

};

输入二叉树中的两个结点,输出这两个结点在数中最低的共同父结点。

 

 

分析一:二叉树是二叉排序树,那么位于左子树的节点都比父节点小,而位于右子树的节点都比父节点大,我们只需要从树的根节点开始和两个输入的节点进行比较。如果当前节点的值比两个节点的值都大,那么最低的共同父节点一定在当前节点的左子树中,于是下一步遍历当前节点的左子结点。如果当前节点的值比两个节点的值都小,那么最低共同父节点一定在当前节点的右子树中,于是下一步遍历当前节点的右子结点。这样在树中从上到下找到的第一个在两个输入节点的值之间的节点,就是最低的公共祖先。

 

 

代码:

#ifndef _LOWESTCOMMONPARENT_H_

#define _LOWESTCOMMONPARENT_H_

#include <iostream>

#include <vector>

#include <list>

#include <stdio.h>

 

using namespace std;

 

struct BinaryTreeNode

{

    intm_nValue;

    BinaryTreeNode* m_pLeft;

    BinaryTreeNode* m_pRight;

};

 

//createnode

BinaryTreeNode*CreateBinaryTreeNode(int value)

{

    BinaryTreeNode* pNode=new BinaryTreeNode();

    pNode->m_nValue=value;

    pNode->m_pLeft=pNode->m_pRight=NULL;

 

    returnpNode;

}

 

//addleft child to parent

bool BinaryTreeAddLeftNode(BinaryTreeNode*pParent,BinaryTreeNode* pLeft)

{

    if(pParent==NULL || pLeft==NULL)

    {

        return false;

    }

    if(pParent->m_pLeft!=NULL)

    {

        cout<<pParent->m_nValue<<" has left child"<<endl;

        return false;

    }

    else

    {

        pParent->m_pLeft=pLeft;

        return true;

    }

}

 

//addright child to parent

bool BinaryTreeAddRightNode(BinaryTreeNode*pParent,BinaryTreeNode* pRight)

{

    if(pParent==NULL || pRight==NULL)

    {

        return false;

    }

 

    if(pParent->m_pRight!=NULL)

    {

        cout<<pParent->m_nValue<<" has right node"<<endl;

        return false;

    }

    else

    {

        pParent->m_pRight=pRight;

        return true;

    }

 

}

 

//二叉排序树情况

 BinaryTreeNode* TheFirstCommonNode(BinaryTreeNode*pRoot,BinaryTreeNode* pNode1,BinaryTreeNode* pNode2)

{

    if(pRoot==NULL|| pNode1==NULL || pNode2==NULL)

    {

        returnNULL;

    }

 

    if(pRoot->m_nValue>pNode1->m_nValue&& pRoot->m_nValue<pNode2->m_nValue)

    {

        returnpRoot;

    }

 

    if(pRoot->m_nValue<pNode1->m_nValue&& pRoot->m_nValue<pNode2->m_nValue)

    {

 

        if(pRoot->m_pRight!=NULL)

        {

            return(TheFirstCommonNode1(pRoot->m_pRight,pNode1,pNode2));

        }

    }

 

    if(pRoot->m_nValue>pNode1->m_nValue&& pRoot->m_nValue>pNode2->m_nValue)

    {

        if(pRoot->m_pLeft!=NULL)

        {

            return(TheFirstCommonNode1(pRoot->m_pLeft,pNode1,pNode2));

        }

    }

 

 

}

 

 

int run()

{

    //构建树

    BinaryTreeNode* pRoot =CreateBinaryTreeNode(8);

    BinaryTreeNode* pNode5 =CreateBinaryTreeNode(5);

    BinaryTreeNode* pNode10 =CreateBinaryTreeNode(10);

BinaryTreeNode* pNode4 = CreateBinaryTreeNode(4);

    BinaryTreeNode* pNode6 =CreateBinaryTreeNode(6);

    BinaryTreeNode* pNode9 =CreateBinaryTreeNode(9);

    BinaryTreeNode* pNode11 = CreateBinaryTreeNode(11);

 

    BinaryTreeAddLeftNode(pRoot,pNode5);

    BinaryTreeAddRightNode(pRoot,pNode10);

 

    BinaryTreeAddLeftNode(pNode5,pNode4);

    BinaryTreeAddRightNode(pNode5,pNode6);

 

    BinaryTreeAddLeftNode(pNode10,pNode9);

    BinaryTreeAddRightNode(pNode10,pNode11);

 

    //测试程序

    BinaryTreeNode* pNode =TheFirstCommonNode(pRoot,pNode5,pNode11);

    if(NULL != pNode)

        cout<<pNode->m_nValue<<endl;

 

    system("pause");

    return 0;

}

#endif

 

 

 

分析二:第二个变种是树不一定是二叉树,每个结点都有一个指针指向它的父结点。于是我们可以从任何一个结点出发,得到一个到达树根结点的单向链表。因此这个问题转换为两个单向链表的第一个公共结点。

代码:

#ifndef _LOWESTCOMMONPARENT_H_

#define _LOWESTCOMMONPARENT_H_

#include <iostream>

#include <vector>

#include <list>

#include <stdio.h>

 

using namespace std;

 

struct BinaryTreeNode

{

    intm_nValue;

    BinaryTreeNode* m_pLeft;

    BinaryTreeNode* m_pRight;

};

 

//createnode

BinaryTreeNode*CreateBinaryTreeNode(int value)

{

    BinaryTreeNode* pNode=new BinaryTreeNode();

    pNode->m_nValue=value;

    pNode->m_pLeft=pNode->m_pRight=NULL;

 

    returnpNode;

}

 

//addleft child to parent

bool BinaryTreeAddLeftNode(BinaryTreeNode*pParent,BinaryTreeNode* pLeft)

{

    if(pParent==NULL || pLeft==NULL)

    {

        return false;

    }

    if(pParent->m_pLeft!=NULL)

    {

        cout<<pParent->m_nValue<<" has left child"<<endl;

        return false;

    }

    else

    {

        pParent->m_pLeft=pLeft;

        return true;

    }

}

 

//addright child to parent

bool BinaryTreeAddRightNode(BinaryTreeNode*pParent,BinaryTreeNode* pRight)

{

    if(pParent==NULL || pRight==NULL)

    {

        return false;

    }

 

    if(pParent->m_pRight!=NULL)

    {

        cout<<pParent->m_nValue<<" has right node"<<endl;

        return false;

    }

    else

    {

        pParent->m_pRight=pRight;

        return true;

    }

 

}

 

//t??¨°º¡Â¨¦?

 

BinaryTreeNode*TheFirstCommonNode1(BinaryTreeNode* pRoot,BinaryTreeNode*pNode1,BinaryTreeNode* pNode2)

{

    if(pRoot==NULL|| pNode1==NULL || pNode2==NULL)

    {

        returnNULL;

    }

 

    if(pRoot->m_nValue>pNode1->m_nValue&& pRoot->m_nValue<pNode2->m_nValue)

    {

        returnpRoot;

    }

 

    if(pRoot->m_nValue<pNode1->m_nValue&& pRoot->m_nValue<pNode2->m_nValue)

    {

 

        if(pRoot->m_pRight!=NULL)

        {

            return(TheFirstCommonNode1(pRoot->m_pRight,pNode1,pNode2));

        }

    }

 

    if(pRoot->m_nValue>pNode1->m_nValue&& pRoot->m_nValue>pNode2->m_nValue)

    {

        if(pRoot->m_pLeft!=NULL)

        {

            return(TheFirstCommonNode1(pRoot->m_pLeft,pNode1,pNode2));

        }

    }

 

 

}

 

//获得从pRootpNode的路径,存于path path保存了从pRootpNode的完整路径

 

bool GetNodePath(BinaryTreeNode*pRoot,BinaryTreeNode* pNode,list<BinaryTreeNode*>& path)

{

    if(pRoot==pNode)

    {

        path.push_back(pRoot);

        return true;

    }

 

    path.push_back(pRoot);

 

    bool found=false;

 

    if(pRoot->m_pLeft!=NULL)

    {

        found=GetNodePath(pRoot->m_pLeft,pNode,path);

    }

    if (!found&& pRoot->m_pRight!=NULL)

    {

        found=GetNodePath(pRoot->m_pRight,pNode,path);

    }

 

    if (!found)

    {

        path.pop_back();

    }

 

    returnfound;

}

 

//普通情况找寻节点到根节点的路径

 

BinaryTreeNode*TheFirstCommonNode(BinaryTreeNode* pRoot,BinaryTreeNode* pNode1,BinaryTreeNode*pNode2)

{

    if(pRoot==NULL || pNode1==NULL || pNode2==NULL)

    {

        returnNULL;

    }

 

    BinaryTreeNode* pLastCommonNode;

 

    list<BinaryTreeNode*> path1;

    list<BinaryTreeNode*> path2;

 

    boolgetPath1=GetNodePath(pRoot,pNode1,path1);

    boolgetPath2=GetNodePath(pRoot,pNode2,path2);

 

    if(getPath1==false || getPath2==false)

    {

        return false;

    }

 

    list<BinaryTreeNode*>::const_iteratoriterator1=path1.begin();

    list<BinaryTreeNode*>::const_iteratoriterator2=path2.begin();

 

    while(iterator1!=path1.end()&& iterator2!=path2.end())

    {

        if(*iterator1==*iterator2)

        {

            pLastCommonNode=*iterator1;

            iterator1++;

            iterator2++;

        }else

        {

            returnpLastCommonNode;

        }

 

    }

 

}

 

int run()

{

    //构建树

 

    BinaryTreeNode* pRoot =CreateBinaryTreeNode(8); 

    BinaryTreeNode* pNode5 =CreateBinaryTreeNode(5); 

    BinaryTreeNode* pNode10 =CreateBinaryTreeNode(10); 

    BinaryTreeNode* pNode4 =CreateBinaryTreeNode(4); 

    BinaryTreeNode* pNode6 =CreateBinaryTreeNode(6); 

    BinaryTreeNode* pNode9 =CreateBinaryTreeNode(9); 

    BinaryTreeNode* pNode11 =CreateBinaryTreeNode(11); 

 

    BinaryTreeAddLeftNode(pRoot,pNode5); 

    BinaryTreeAddRightNode(pRoot,pNode10); 

 

    BinaryTreeAddLeftNode(pNode5,pNode4); 

    BinaryTreeAddRightNode(pNode5,pNode6); 

 

    BinaryTreeAddLeftNode(pNode10,pNode9); 

    BinaryTreeAddRightNode(pNode10,pNode11); 

 

    //测试程序 

    BinaryTreeNode* pNode =TheFirstCommonNode(pRoot,pNode6,pNode11); 

    if(NULL !=pNode) 

        cout<<pNode->m_nValue<<endl; 

    system("pause");

    return 0;

}

#endif

 

如果没有指向父节点的指针的话,我们的主要问题就是怎么能得到从根节点分别到这两个节点的两条链表?

 

问题关键点:分析如果是二叉排序树的本身特性进行求解,若是普通情况则进行求路径找公共父节点

参考至:http://blog.csdn.net/attitudeisaltitude/article/details/9847245

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值