1. 程式人生 > >二叉樹中兩個節點的最近公共父節點

二叉樹中兩個節點的最近公共父節點

轉載:http://blog.csdn.net/hackbuteer1/article/details/8022138#

這個問題可以分為四種情況來考慮:
情況一:root未知,但是每個節點都有parent指標
此時可以分別從兩個節點開始,沿著parent指標走向根節點,得到兩個連結串列,然後求兩個連結串列的第一個公共節點,這個方法很簡單,不需要詳細解釋的。

情況二:節點只有左、右指標,沒有parent指標,root已知
思路:有兩種情況,一是要找的這兩個節點(a, b),在要遍歷的節點(root)的兩側,那麼這個節點就是這兩個節點的最近公共父節點;
二是兩個節點在同一側,則 root->left 或者 root->right 為 NULL,另一邊返回a或者b。那麼另一邊返回的就是他們的最小公共父節點。
遞迴有兩個出口,一是沒有找到a或者b,則返回NULL;二是隻要碰到a或者b,就立刻返回。


說明:這個遞迴的解法是不完整的,對於a,b不全在二叉樹中的情況,並沒有考慮到。

// 二叉樹結點的描述    
struct Node    
{    
    int data;    
    Node *lchild, *rchild;      // 左右孩子    
	Node(int x):data(x),lchild(NULL),rchild(NULL){}
};
  
// 節點只有左指標、右指標,沒有parent指標,root已知  
Node* findLowestCommonAncestor(Node* root , Node* a , Node* b){  
	if(root==NULL)
		return NULL;
	if(root==a||root==b)
		return root;
	Node* left = findLowestCommonAncestor(root->lchild,a,b);
	Node* right= findLowestCommonAncestor(root->rchild,a,b);
	if(left&&right)
		return root;
	return left?left:right;
}  

int main(){ 
	Node* v15 = new  Node(15);
	Node* v8  = new  Node(8);
	Node* v25 = new  Node(25);
	Node* v30 = new  Node(30);
	v15->lchild = v8;
	v15->rchild = v25;
	auto res = findLowestCommonAncestor(v15,v8,v30);
	cout<<res->data<<endl;
}

情況三: 二叉樹是個二叉查詢樹,且root和兩個節點的值(a, b)已知
//二叉樹結點的描述    
struct Node{    
    int data;    
    Node *lchild, *rchild;      // 左右孩子    
	Node(int x):data(x),lchild(NULL),rchild(NULL){}
};
  
//待查詢的是排序二叉搜尋樹
Node* findLowestCommonAncestor(Node* root , Node* a , Node* b){  
	if(root==NULL)
		return root;
	int min = a->data < b->data ? a->data:b->data;
	int max = a->data > b->data ? a->data:b->data;
	while(root){
		if(root->data>min && root->data < max)
			return root;
		if(root->data > min && root->data > max)
			root = root->lchild;
		else
			root = root->rchild;
	}
	return NULL;
}  

int main(){ 
	Node* v15 = new  Node(15);
	Node* v8  = new  Node(8);
	Node* v25 = new  Node(25);
	Node* v30 = new  Node(30);
	Node* v7  = new  Node(7);
	Node* v9  = new  Node(9);
	Node* v20 = new  Node(20);
	v15->lchild = v8;
	v15->rchild = v25;
	v25->lchild = v20;
	v25->rchild = v30;
	v8->lchild = v7;
	v8->rchild = v9;
	auto res = findLowestCommonAncestor(v15,v20,v30);
	cout<<res->data<<endl;
}

情況四:上述的適用於二叉樹,但是如果給的樹不是二叉樹。那麼有個通用的解法,就是將根結點到目標結點的路徑先儲存下來。然後,再去尋找公共的父節點。時間複雜度O(n)。

//二叉樹結點的描述    
struct Node{    
    int data;    
    Node *lchild, *rchild;      // 左右孩子    
	Node(int x):data(x),lchild(NULL),rchild(NULL){}
};
 
//尋找從根結點到父節點的path
bool GetNodePath(Node* root,Node* target,vector<Node*>& path){
	if(root==NULL)
		return false;
	if(root == target)
		return true;
	path.push_back(root);
	bool found = false;
	if(!found) found = GetNodePath(root->lchild,target,path);
	if(!found) found = GetNodePath(root->rchild,target,path);
	if(!found) path.pop_back();
	return found;
}

//尋找最近的公共父節點
Node* GetLastCommonNode(const vector<Node*>& path1,const vector<Node*>& path2){
	int len1 = path1.size();
	int len2 = path2.size();
	int len = len1 < len2 ? len1:len2;
	Node* LastCommon = NULL;
	for(int i=0;i<len;i++){
		if(path1[i]==path2[i])
			LastCommon = path1[i];
		else
			break;
	}
	return LastCommon;
}

//尋找最小公共父節點
Node* GetLastCommonParent(Node* root,Node* pNode1,Node* pNode2){
	if(root==NULL||pNode1==NULL||pNode2==NULL)
		return NULL;
	vector<Node*> path1;
	bool flag1= GetNodePath(root,pNode1,path1);
	vector<Node*> path2;
	bool flag2= GetNodePath(root,pNode2,path2);
	if(flag1&&flag2)
		return GetLastCommonNode(path1,path2);
	else
		return NULL;
}