1. 程式人生 > >求兩個節點最近的公共祖先

求兩個節點最近的公共祖先

(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);
       }