找寻二叉树中两个节点的公共父节点中最近的那个节点的三种情况

来源:互联网 发布:手机登陆电脑版淘宝 编辑:程序博客网 时间:2024/06/10 13:03

来源:http://blog.csdn.net/wangyangkobe/article/details/6527858

找寻二叉树中两个节点的公共父节点中最近的那个节点

    10

                                         /   /

                                        6    14

                                      /  /    /  /

                                    4    8 12 16

                                   / /

                                 3   5

情况1. root未知,但是每个节点都有parent指针.

分析:如果我们要找3和8这两个节点的公共父亲节点,我们的做法是首先找到3到根节点的路劲,然后找到8到根节点的路径。

可以看到, 这里的问题实际上是另一个我们熟知的问题,有2个相交的单链表,找出它们的相交点!

只要把这个二叉树的图片倒过来看,或者把脖子倒过来看就知道了,那个方法也是传统的求出linkedList A的长度lengthA, linkedList B的长度LengthB。然后让长的那个链表走过abs(lengthA-lengthB)步之后,齐头并进,就能解决了。

view plain
  1. //节点结构体(包含父节点)  
  2. struct Node  
  3. {  
  4.     Node *lChild;  
  5.     Node *rChild;  
  6.     Node *parent;  
  7.     int element;  
  8.     Node(int ele, Node *m_parent = NULL, Node *left = NULL, Node *right = NULL)  
  9.         :element(ele), parent(m_parent), lChild(left), rChild(right){}  
  10. };  
  11. //创建树  
  12. Node* CreateTree(Node *root, int arr[], int cur, int len)  
  13. {  
  14.     root = new Node(arr[cur], root); //根节点的父节点为null  
  15.     if (2*cur + 1 < len)  
  16.         root->lChild = CreateTree(root, arr, 2*cur + 1, len);  
  17.     if (2*cur + 2 < len)  
  18.         root->rChild = CreateTree(root, arr, 2*cur + 2, len);  
  19.     return root;  
  20. }  
  21. //返回节点值为element的节点指针  
  22. Node *FindNode(Node *root, int element)  
  23. {  
  24.     if (NULL == root)  
  25.         return NULL;  
  26.     else if (element == root->element)  
  27.         return root;  
  28.     else   
  29.     {  
  30.         Node *result = NULL;  
  31.         Node *l_res = FindNode(root->lChild, element);  
  32.         Node *r_res = FindNode(root->rChild, element);  
  33.         if(NULL != l_res)  
  34.             result = l_res;  
  35.         else if(NULL != r_res)  
  36.             result = r_res;  
  37.         return result;  
  38.     }  
  39. }  
  40. //返回节点node到根节点的root的距离  
  41. int GetLengthToRoot(Node *root, Node *node)  
  42. {  
  43.     assert(node && root);  
  44.     int res = 0;  
  45.     while (node->parent != root)  
  46.     {  
  47.         res++;  
  48.         node = node->parent;  
  49.     }  
  50.     return res;  
  51. }  
  52. //函数功能:查找节点node1和node2的最近公共父节点  
  53. //算法思路:和求两个链表的节点的方法一样  
  54. //A先走到root,计数为An,B走到Root,计数为Bn,不失一般性,假设An>Bn,  
  55. //那么再来一次,A先往parent方向走An-Bn步,然后两个一起走,碰头(遇到相同节点)的时候就是最近公共父节点了  
  56. Node *FindNearestCommonParent(Node *root, Node *node1, Node *node2)  
  57. {  
  58.     int path1 = GetLengthToRoot(root, node1);  
  59.     int path2 = GetLengthToRoot(root, node2);  
  60.     Node *longPath = (path1 > path2) ? node1 : node2;  
  61.     Node *shortPath = (path1 > path2) ? node2 : node1;  
  62.       
  63.     int step = abs(path2 - path1);  
  64.     for(int i = 0; i < step; i++)  
  65.         longPath = longPath->parent;  
  66.     while (longPath && shortPath)  
  67.     {  
  68.         if(longPath == shortPath)  
  69.             return longPath;  
  70.         longPath = longPath->parent;  
  71.         shortPath = shortPath->parent;  
  72.     }  
  73. }  
  74. int main()  
  75. {  
  76.     int arr[] = {10, 6, 14, 4, 8, 12, 16, 3, 5};  
  77.     int len = sizeof(arr)/ sizeof(*arr);  
  78.     Node *root = NULL;  
  79.     root = CreateTree(root, arr, 0, len);  
  80.     Node *node1 = FindNode(root, 3);  
  81.     Node *node2 = FindNode(root, 8);  
  82.     Node *common = FindNearestCommonParent(root, node1, node2);  
  83.     cout<<"The nearest common parent node is: "<<common->element<<endl;  
  84.     system("pause");  
  85. }  
 

 

 


情况2. 节点只有left/right,没有parent指针,root已知.

view plain
  1. //节点结构体  
  2. struct Node  
  3. {  
  4.     Node *lChild;  
  5.     Node *rChild;  
  6.     int element;  
  7.     Node(int ele, Node *left = NULL, Node *right = NULL)  
  8.         :element(ele), lChild(left), rChild(right){}  
  9. };  
  10. //创建树  
  11. Node* CreateTree(Node *root, int arr[], int cur, int len)  
  12. {  
  13.     root = new Node(arr[cur]);  
  14.     if (2*cur + 1 < len)  
  15.         root->lChild = CreateTree(root, arr, 2*cur + 1, len);  
  16.     if (2*cur + 2 < len)  
  17.         root->rChild = CreateTree(root, arr, 2*cur + 2, len);  
  18.     return root;  
  19. }  
  20. //返回节点值为element的节点指针  
  21. Node *FindNode(Node *root, int element)  
  22. {  
  23.     if (NULL == root)  
  24.         return NULL;  
  25.     else if (element == root->element)  
  26.         return root;  
  27.     else   
  28.     {  
  29.         Node *result = NULL;  
  30.         Node *l_res = FindNode(root->lChild, element);  
  31.         Node *r_res = FindNode(root->rChild, element);  
  32.         if(NULL != l_res)  
  33.             result = l_res;  
  34.         else if(NULL != r_res)  
  35.             result = r_res;  
  36.         return result;  
  37.     }  
  38. }  
  39. //函数功能:查找节点node1和node2的最近公共父节点,result为最近公共祖先节点的指针的指针  
  40. //算法思想:如果一个节点的左子树包含p,q中的一个节点,右子树包含另一个,则这个节点就是p,q的最近公共祖先。  
  41. int FindNearestCommonParent(Node *root, Node *node1, Node *node2, Node **result)  
  42. {  
  43.     if(NULL == root)  
  44.         return 0;  
  45.     if(root == node1 || root == node2)  
  46.         return 1;  
  47.     int left = FindNearestCommonParent(root->lChild, node1, node2, result);  
  48.     if (2 == left)  
  49.         return 2;  
  50.     int right = FindNearestCommonParent(root->rChild, node1, node2, result);  
  51.     if(2 == right)  
  52.         return 2;  
  53.     if (left + right == 2)  
  54.     {  
  55.         *result = root;  
  56.         return 2;  
  57.     }  
  58. }  
  59. int main()  
  60. {  
  61.     int arr[] = {10, 6, 14, 4, 8, 12, 16, 3, 5};  
  62.     int len = sizeof(arr)/ sizeof(*arr);  
  63.     Node *root = NULL;  
  64.     root = CreateTree(root, arr, 0, len);  
  65.     Node *node1 = FindNode(root, 3);  
  66.     Node *node2 = FindNode(root, 16);  
  67.     Node *result = NULL;  
  68.     int res = FindNearestCommonParent(root,  node1, node2, &result);  
  69.     if(2 == res)  
  70.         cout<<result->element<<endl;  
  71.     system("pause");  
  72. }  
 

 

情况3. 二叉树是个二叉查找树,且root和两个节点的值(a, b)已知。


view plain
  1. //节点结构体  
  2. struct Node  
  3. {  
  4.     Node *lChild;  
  5.     Node *rChild;  
  6.     int element;  
  7.     Node(int ele, Node *left = NULL, Node *right = NULL)  
  8.         :element(ele), lChild(left), rChild(right){}  
  9. };  
  10. //函数功能:递归想二叉查找树中插入节点  
  11. void InsertNode(Node *&root, int ele)  
  12. {  
  13.     if (root == NULL)  
  14.         root = new Node(ele);  
  15.     else if(ele < root->element)  
  16.          InsertNode(root->lChild, ele);  
  17.     else if (ele > root->element)  
  18.         InsertNode(root->rChild, ele);  
  19. }  
  20. //创建树  
  21. Node* CreateBSTree(int arr[], int len)  
  22. {  
  23.     Node *root = NULL;  
  24.     for (int i = 0; i < len; i++)  
  25.     {  
  26.         InsertNode(root, arr[i]);  
  27.     }  
  28.     return root;  
  29. }  
  30. //返回节点值为element的节点指针  
  31. Node *FindNode(Node *root, int element)  
  32. {  
  33.     if (NULL == root)  
  34.         return NULL;  
  35.     else if (element == root->element)  
  36.         return root;  
  37.     else   
  38.     {  
  39.         Node *result = NULL;  
  40.         Node *l_res = FindNode(root->lChild, element);  
  41.         Node *r_res = FindNode(root->rChild, element);  
  42.         if(NULL != l_res)  
  43.             result = l_res;  
  44.         else if(NULL != r_res)  
  45.             result = r_res;  
  46.         return result;  
  47.     }  
  48. }  
  49. //函数功能:查找节点node1和node2的最近公共父节点,result为最近公共祖先节点的指针的指针  
  50. //算法思想:充分利用二叉查找数的性质  
  51. Node* FindNearestCommonParent(Node *root, Node *node1, Node *node2)  
  52. {  
  53.     while (root != NULL)  
  54.     {  
  55.         int ele = root->element;  
  56.         if (ele < node1->element && ele < node2->element)  
  57.             root = root->rChild;  
  58.         else if (ele > node1->element && ele > node2->element)  
  59.             root = root->lChild;  
  60.         else  
  61.             break;  
  62.     }  
  63.     return root;  
  64. }  
  65. int main()  
  66. {  
  67.     int arr[] = {10, 6, 14, 4, 8, 12, 16, 3, 5};  
  68.     int len = sizeof(arr)/ sizeof(*arr);  
  69.     Node *root = NULL;  
  70.     root = CreateBSTree(arr, len);  
  71.     Node *node1 = FindNode(root, 3);  
  72.     Node *node2 = FindNode(root, 5);  
  73.     Node *res = FindNearestCommonParent(root, node1, node2);  
  74.     cout<<res->element<<endl;  
  75.     system("pause");  
  76. }  


**************************************************************************************************

实际上,用树的后序遍历就可以了。当访问到所求的节点A时,如果这两个节点不在一条线上,则它们必定分别在A的左子树和右子树上,后序遍历到第一个满足这个条件的节点就是所要求的节点A。另外,还必须对这两个节点在一条线上的情况,做特殊处理。

代码:

static bool lca(Node *root, int va, int vb, Node *&result, Node* parrent)
{
  // left/right 左/右子树是否含有要判断的两节点之一 
  bool left = false, right = false;
  if (!result && root->left) left = lca(root->left,va,vb,result,root);
  if (!result && root->right) right = lca(root->right,va,vb,result,root);
  // mid 当前节点是否是要判断的两节点之一 
  bool mid = false;
  if (root->data == va || root->data == vb) mid=true;
  if (!result && int(left + right + mid) == 2) {
    if (mid) result = parrent;
    else result = root;
  }
  return left | mid | right ;
}

Node *lca(Node *root,int va, int vb)
{
  if (root == NULL) return NULL;
  Node *result = NULL;
  lca(root, va, vb,result, NULL);
  return result;
}

原创粉丝点击