zoukankan      html  css  js  c++  java
  • 【转】二叉树中两个节点的最近的公共父节点

    原文地址: 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;  
        }  
  • 相关阅读:
    让UIButton在按下时没有高亮效果
    如何让View一直沿z轴旋转
    App 应用通过网页打开 App Store
    Xcode/iOS: 如何判断代码运行在DEBUG还是RELEASE模式下?
    freemyapps 推荐链接
    [转]Git使用基础篇
    [转]anchorPoint 锚点解析
    Mac下如何看Swf文件
    Xcode 5: 将新项目同步到Svn上
    Shell 启动java程序
  • 原文地址:https://www.cnblogs.com/cyttina/p/2740365.html
Copyright © 2011-2022 走看看