求两个节点最近的公共祖先

来源:互联网 发布:金山软件太原公司 编辑:程序博客网 时间:2024/05/08 06:03
(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);       }