1. 程式人生 > >二叉樹中兩個節點的最近公共祖先節點方法全集

二叉樹中兩個節點的最近公共祖先節點方法全集

一.如果資料結構為三叉連結串列,即含有指向父節點的指標:

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裡有沒有此節點,有則找到所以的祖先節點,沒有就繼續找)