【转】二叉树中两个节点的最近的公共父节点
原文地址: 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; }