求兩個節點最近的公共祖先
阿新 • • 發佈:2019-01-06
(1)如果這棵樹是二叉搜尋樹
二叉搜尋樹是排序過的,位於左子樹的節點的值比當前節點的值小,而位於右子樹的節點的值都比當前節點的值大。我們只需要從樹的根節點開始和兩個輸入的節點進行比較。
(1)如果當前節點的值比兩個節點的值都大,那麼最近公共祖先一定在當前節點的左子樹裡。於是下一步遍歷當前節點的左子樹的節點。
(2)如果當前節點的值比兩個節點的值都小,那麼最近公共祖先一定在當前節點的右子樹裡,於是下一步遍歷當前節點的右子樹的節點。
(3)從根節點開始從上到下,第一個當前節點的值在兩個節點值的中間,那麼這個節點就是兩個節點的最近公共祖先。
Node* BSTNearCommAncestor(Node* left, Node* right)
{
if (_root == NULL)
{
return NULL;
}
Node* cur = _root;
while (cur)
{
if (cur->_data > left->_data && cur->_data > right->_data)
{
cur = cur->_left;
}
else if (cur->_data < left->_data && cur->_data < right->_data)
{
cur = cur->_right;
}
else
{
break;
}
}
if (cur)
{
return cur;
}
return NULL;
}
(2)如果這棵樹不是二叉搜尋樹,並且這棵樹是帶有父節點的一棵樹。
如果樹中的每個節點都都有一個指向父節點的指標,那麼這個問題可以轉換成求兩個連結串列的第一個公共的節點。每個節點的父親一定是唯一的,那麼從一個節點向上遍歷,那麼根節點一定會是一條連結串列的最後一個節點。那麼兩個節點向上一直到根節點,一定是兩條相交的連結串列,這時候將問題看成是求兩條連結串列相交的交點,那麼這個點一定是兩個節點的最近公共祖先。 Node* ParentNearCommAncestor(Node* left, Node* right)
{
if (_root == NULL)
{
return NULL;
}
vector<Node*> v1;
vector<Node*> v2;
while (left)
{
v1.push_back(left);
left = left->_parent;
}
while (right)
{
v2.push_back(right);
right = right->_parent;
}
Node* cur = NULL;
int len = v1.size() < v2.size() ? v1.size() : v2.size();
while (len--)
{
if (v1[len] == v2[len])
{
cur = v1[len];
}
else
{
break;
}
}
return cur;
}
(3)如果這棵樹不是二叉搜尋樹,樹上的每一個節點也沒有指向父親節點的指標
方法一:
我們首先要得到一條從根節點到樹中某一個節點的路徑,這就要求在遍歷的時候,有一個輔助記憶體來儲存路徑。然後我們求出兩條路徑下最後一個相同的公共節點,那麼這個節點就是兩個節點的最近公共祖先。
void GetNodePath(Node* root,const Node*& node, vector<Node*>& v, const bool& flag)
{
if (root == NULL || flag == true)
{
//空?節??點??或??者?是??已??經-找??到??node節??點??的??情??況?下?無T需??繼??續?遞?Y歸??了??
return;
}
GetNodePath(root->_left, node, v,flag);
GetNodePath(root->_right, node, v,flag);
if (root == node || flag == true)
{
//找??到??這a個?節??點??或??者?是??已??經-找??到??這a個?節??點??路??徑?上??的??其?他?節??點??需??要?a添???加??到??路??徑?中D
v.push_back(root);
flag = true;
}
}
Node* NearCommAncestor(Node* left, Node* right)
{
if (_root == NULL || left == NULL || right == NULL)
{
return;
}
vector<Node*> v1;
GetNodePath(_root, left, v1, false);
vector<Node*> v2;
GetNodePath(_root, right, v2, false);
int i = 0;
while ((i < v1.size() - 1) && (i < v2.size() - 1))
{
if (v1[i+1] != v2[i+1])
{
break;
}
else
{
++i;
}
}
if ((i < v1.size() - 1) && (i < v2.size() - 1))
{
return v1[i];
}
return NULL;
}
方法二:
我們可以後序遍歷這棵二叉樹,用left記錄左子樹返回的結果,用right記錄右子樹返回的結果。當左右子樹都不為空的時候,返回當前節點表示已經找到了兩個節點的最近公共祖先。
Node* _NearCommAncestor(Node* root, Node* node1, Node* node2)
{
if (root == NULL)
{
return NULL;
}
Node* left = _NearCommAncestor(root->_left, node1, node2);
Node* right = _NearCommAncestor(root->_right, node1, node2);
if (left && right)
{
return root;
}
if (root == node1)
{
return node1;
}
if (root == node2)
{
return node2;
}
if (left == NULL && right)
{
return right;
}
if (right == NULL && left)
{
return left;
}
}
Node* NearCommAncestor(Node* node1, Node* node2)
{
return _NearCommAncestor(_root, node1, node2);
}