【转】二叉树中两个节点的最近的公共父节点

原文地址: http://blog.csdn.net/jackyliujin/article/details/7581727

情况1. 节点只有left/right,没有parent指针,root已知

情况2. root未知,但是每个节点都有parent指针

情况3. 二叉树是个二叉查找树,且root和两个节点的值(a, b)已知

--------------------------------------------------------------------------------

虽然情况一是第一个情况,但是看上去比较复杂,我们放到最后来说,先从第二个情况开始说。

                                            10

                                          /      \
                                        6         14
                                      /   \       /  \
                                   4      8   12   16

                                  /  \

                                 3   5

画一个二叉树来做例子。如果我们要找3和8这两个节点的公共父亲节点,我们的做法是首先找到3到根节点的路劲,然后找到8到根节点的路径。

                                            10

                                          /      \
                                        6         14
                                      /   \       /  \
                                   4      8   12   16

                                  /  \

                                 3   5

这里就可以转为求两个链表的公共节点的问题。

只要把这个二叉树的图片倒过来看,或者把脖子倒过来看就知道了:)那个方法也是传统的求出linkedList A的长度lengthA, linkedList B的长度LengthB。然后让长的那个链表走过abs(lengthA-lengthB)步之后,齐头并进,就能解决了。

代码(改进了一下原文代码):

    int getLength (bstNode* pNode)     
    {        
        int length = 0;     
        bstNode* pTemp = pNode;     
        while (pTemp)     
        {     
            length ++ ;     
            pTemp = pTemp->pParent;     
        }     
        return length;     
    }     
    bstNode* findLCACase2(bstNode* pNode1, bstNode* pNode2)     
    {     
        int length1 = getLength(pNode1);     
        int length2 = getLength(pNode2);     
             
        // skip the abs(length1-length2)     
        bstNode* pIter1 = pNode1;     
        bstNode* pIter2 = pNode2;
        int offset = length1 - length2;
        if(length1 < length2)
        {
            offset = length2 - length1;
            pIter1 = pNode2;
            pIter2 = pNode1;
        }
        // 这样pIter1中始终保持着长的链表
        // 将pIter1移动offset次之后,pIter1和pIter2一起移动就可以了
        for(int i=0; i<offset; i++)
            pIter1 = pIter1->next;
        
        // 一起移动     
        while (pIter1&&pIter2&&pIter1!= pIter2)     
        {     
            pIter1 = pIter1->pParent;     
            pIter2 = pIter2->pParent;     
        }     
        return pIter1;     
    }    

 


还是原来这个图,情况三,如果是个二叉搜索树,而且root和a, b已知,我们这个case假设a,b=3,8。

因为是二叉搜索树,如果存在公共节点,则公共节点必然在3和8之间,用树的中序遍历就可以搞定这个问题。

代码如下:

    template<typename T>  
    TreeNode1<T>* FindNearestParentNode(TreeNode1<T>* pRoot, T a, T b)  
    {  
     if(a > b)  
     {  
      T temp = a;  
      a = b;  
      b = a;  
     }  
     while(pRoot)  
     {  
      if(pRoot->data >= a && pRoot->data <= b)  
       return pRoot;  
      else if(pRoot->data < a && pRoot->data < b)  
       pRoot = pRoot->pLChild;  
      else  
       pRoot = pRoot->pRChild;  
     }  
     return NULL;  
    }  

 


对于情况一,其实和情况二差不多,只是需要我们通过先序遍历找到这两个链表,之后在求公共链表的最近相交节点即可。

    template<typename T>  
    struct TreeNode1  
    {  
     T data;  
     TreeNode1* pLChild;  
     TreeNode1* pRChild;  
    };  
      
    #include <vector>  
      
    // 找寻节点路径,倒序,根节点在最后  
    template<typename T>  
    bool FindNodePath(TreeNode1<T>* pRoot, TreeNode1<T>* p, std::vector<TreeNode1<T>*>& path)  
    {  
     if(pRoot == NULL)  
      return false;  
     if(p == pRoot)  
     {  
      path.push_back(pRoot);  
      return true  
     }  
     else if(FindNodePath(pRoot->pLChild, p, path))  
     {  
      path.push_back(pRoot->pLChild);  
      return true;  
     }  
     else if(FindNodePath(pRoot->pRChild, p, path))  
     {  
      path.push_back(pRoot->pRChild);  
      return true;  
     }  
     return false;  
    }  
    template<typename T>  
    TreeNode1<T>* FindNearestParentNode(TreeNode1<T>* pRoot, TreeNode1<T>* p1, TreeNode1<T>* p2)  
    {  
     std::vector<TreeNode1<T>*> path1, path2;  
     bool bFind = FindNodePath(pRoot, p1, path1);  
     bFind &= FindNodePath(pRoot, p2, path2);  
     if(!bFind)  
      return NULL;  
      
     TreeNode1<T>* pReturn = NULL;  
     size_t minSize = path1.size() > path2.size() ? path2.size() : path1.size();  
      
    // 起始点设在可能出现共同节点的部分的起点  
     for(size_t i = path1.size() - minSize, j = path2.size()-minSize; i < path1.size() && j < path2.size(); ++i, ++j)  
     {  
      if(path1[i] == path2[j])  
      {  
       pReturn = path1[i];  
      }  
     }  
      
     return pReturn;  
    }  
posted @ 2012-10-25 23:06  三更_雨  阅读(639)  评论(0编辑  收藏  举报