一.如果数据结构为三叉链表,即含有指向父节点的指针:
Node * NearestCommonAncestor(Node * root,Node * p,Node * q) { Node * temp; while(p!=NULL) { p=p->parent; temp=q; while(temp!=NULL) { if(p==temp->parent) return p; temp=temp->parent; } } }
以上方法叫双重循环法,上面的算法实际上是将一个结点回退到父结点,每退一步,另一个结点指针将回退到不能退为止。此过程来判断它们两结点是否有共同的父母。
检查当前节点;如果value1和value2都小于当前节点的值,检查它的左子节点;如果value1和value2都大于当前节点的值,检查它的右子节点;否则,当前节点就是最近共同祖先。
Node* findLowerstCommonAncestor(Node* root, int value1, int value2) { while ( root != NULL ) { int value = root->getValue(); if ( value > value1 && value > value2 ) root = root->getLeft(); else if (value < value1 && value < value2) root = root->getRight(); else return root; } return NULL; }
bool Getpath(BinaryTreeNode<int>* root,BinaryTreeNode<int>* str1, list<BinaryTreeNode<int>*>& List) //寻找路径 { if(root == NULL || str1 == NULL) //如果其中的一个为空,便不成立 return false; if(root == str1) //如果第一个就是,并且与跟节点相同,便返回 { List.push_back(root); return true; } List.push_back(root);//先压左 bool juge = Getpath(root->_left,str1,List); if(!juge) //在左不成立的情况下,才压右
juge = Getpath(root->_right,str1,List); if(!juge) //把不成立的数据弹出 List.pop_back(); return juge; } BinaryTreeNode<int>* CommonAncestor(BinaryTreeNode<int>* root,BinaryTreeNode<int>* str1, BinaryTreeNode<int>* str2) { assert(root); assert(str1); assert(str2); //断言,确保传值 if(root == NULL || str1 == NULL || str2 ==NULL) //判断条件是否成立 return NULL; if(root == str1 || root == str2) //如果根节点等于其中的一个,便说明,没有公共祖先节点 return NULL; list<BinaryTreeNode<int>*> List1; list<BinaryTreeNode<int>*> List2; bool juge1 = Getpath(root,str1,List1); bool juge2 = Getpath(root,str2,List2); if(juge1 == false || juge2 == false) return NULL; BinaryTreeNode<int> * commonParent=NULL; list<BinaryTreeNode<int>*>::iterator ite1=List1.begin(); list<BinaryTreeNode<int>*>::iterator ite2=List2.begin(); for(;ite1!=List1.end() && ite2!=List2.end();ite1++,ite2++) //寻找最近公共节点 { if(*ite1==*ite2) commonParent=*ite1; else break; } return commonParent; }此处借用了队列的用法,把到两个节点的路径分别加入到两个队列中,因为都是从根向下遍历,开始节点都是相同的,所以,最后一次相同的节点,就是距离他们最近的公共节点。
思想
活用Hash表:
如果每个节点有指向父节点的指针,那么逆向遍历两个节点的所有祖先节点,找第一个一样的祖先,可用hash表存储,
时间复杂度是树的深度,空间复杂度也是数的深度。
可以将q到头结点建立一张Hash表,然后从p到头结点,边遍历边查找Hash表,直到第一次在hash表在哦个查找到节点值存在。
(其实我们可以简单的过程来看思想二的算法:我们可以开辟指向节点的指针数组,先从一个节点下手,让它一直回退,每退一步,数组新的位置记录下它,即指向该节点,直到第一个节点回退完,再进行第二个节点的回退,每退一步就检查一下它在数组中有没有,这样和思想一是一样的,故为了加速,这里应该将每一个节点的回退过程的地址扔进hashset里去,在回退第二个节点时,查一下hashset里有没有此节点,有则找到所以的祖先节点,没有就继续找)