二叉樹中兩個節點的最近公共父節點
阿新 • • 發佈:2019-02-12
轉載: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;
}