首页 > 代码库 > 二叉树——查找两个任意节点的最近祖先

二叉树——查找两个任意节点的最近祖先

很久没有用过二叉树了,最近由于需要用到了,发现很多知识需要巩固了,中间涉及到一个算法就是找任意两个节点的最近祖先。通过本人回顾和演算,最终提出了下面一个方法,网上也有很多其他的方式实现,再次仅对自己好几个小时的工作作个记录和积累吧! 程序是用C语言写的,个人觉得如果用C#实现会更加方便。

首先是数据结构定义:

 

[cpp] view plaincopyprint?
 
  1. typedef char TElemType;  
  2. typedef bool Status;  
  3.   
  4. typedef struct BiTNode{  
  5.     TElemType data;  
  6.     struct BiTNode * lchild, * rchild;  
  7. }BiTNode, * BiTree;  

 

其次是建树,用树的定义,以先序序列递归方式建立。

 

[cpp] view plaincopyprint?
 
  1. BiTNode * CreateBiTree()   
  2. {  
  3.     char ch;  
  4.     BiTNode * T;  
  5.     scanf("%c",&ch);  
  6.     if(ch==‘#‘)  
  7.         T = 0;  
  8.     else  
  9.     {  
  10.         T = (BiTree)malloc(sizeof(BiTNode));  
  11.         T->data = ch;  
  12.         T->lchild = CreateBiTree();  
  13.         T->rchild = CreateBiTree();  
  14.     }  
  15.     return T;  
  16. }  


空节点的分隔符本处使用的是“#”,可以用其他字符替代。

 

查找最近祖先的基本算法是递归,对每个节点先判断是否有直接关联,都没有就分别获得各自的直系父节点,递归调用时需要通过两个节点的深度来判断下一次调用时用哪个使用父节点。具体实现如下:

 

[cpp] view plaincopyprint?
 
  1. //查找两个节点的最近的公共祖先节点  
  2. BiTNode * FindNearestAncestor(BiTNode * root, BiTNode* p1, BiTNode* p2, int h1, int h2)   
  3. {  
  4.     if(!p1 || !p2) return 0;  
  5.     if (p1 == p2)  
  6.     {  
  7.         if (p1 == root) return root;  
  8.         return p1;  
  9.     }     
  10.     if (p1 == p2->lchild || p1 == p2->rchild)  
  11.         return p2;  
  12.     if (p2 == p1->lchild || p2 == p1->rchild)  
  13.         return p1;  
  14.       
  15.     if (h1 == h2)  
  16.         return FindNearestAncestor(  
  17.                     root,   
  18.                     GetParent(root, p1),  
  19.                     GetParent(root, p2),   
  20.                     h1 - 1,   
  21.                     h2 - 1);  
  22.     else  
  23.         return FindNearestAncestor(  
  24.                     root,   
  25.                     h1 > h2 ? GetParent(root, p1) : p1,  
  26.                     h1 < h2 ? GetParent(root, p2) : p2,  
  27.                     h1 > h2 ? h1 - 1 : h1,   
  28.                     h1 < h2 ? h2 - 1 : h2);  
  29. }  


其中GetParent是获取以root为树根的树中p节点的直系父节点,定义如下:

 

 

[cpp] view plaincopyprint?
 
  1. BiTNode * GetParent(BiTNode* root, BiTNode * p)  
  2. {  
  3.     if(!root || p == root) return 0;  
  4.     if(p == root->lchild || p == root->rchild)  
  5.     {  
  6.         return root;  
  7.     }  
  8.     else  
  9.     {  
  10.         return GetParent(root->lchild, p) == 0 ?  
  11.                GetParent(root->rchild, p) : GetParent(root->lchild, p);  
  12.     }  
  13. }  

在主函数中调用如下:

 

 

[csharp] view plaincopyprint?
 
  1. int main()  
  2. {  
  3.     //测试序列: abc###de##fg###   
  4.     printf("请输入前序序列,空节点用‘#’代替:\n");  
  5.     BiTree tree = CreateBiTree();  
  6.         BiTNode * node = FindNearestAncestor(   tree,   
  7.           tree->rchild->lchild,   
  8.               tree->rchild->rchild->lchild,  
  9.           GetHeight(tree,tree->rchild->lchild),  
  10.           GetHeight(tree,tree->rchild->rchild->lchild)  
  11.     );  
  12.   
  13.     printf("节点%c和节点%c的最近父节点为:%c\n",   
  14.         tree->rchild->lchild->data,  
  15.         tree->rchild->rchild->lchild->data,  
  16.         node->data);  
  17.     return 0;  
  18. }  


上述使用了GetHeight函数,用来获取给定树中节点p的高度,这个函数的实现耗费了较多时间,主要是以前都是获取树的高度,很少获取指定节点的高度,其实现如下:

 

 

[cpp] view plaincopyprint?
 
  1. //查找节点p的高度,注意与单纯只计算树的高度不同   
  2. int GetHeight(BiTNode* root, BiTNode * p, int h = 1)  
  3. {  
  4.     if (!root) return 0;  
  5.     if (p == root->lchild || p == root->rchild) return h + 1;  
  6.     return  GetHeight(root->lchild, p, h+1) == 0 ?   
  7.             GetHeight(root->rchild, p, h+1) : GetHeight(root->lchild, p, h+1);  
  8. }  


上述测试使用的先序序列为

 

abc###de##fg###

对应的二叉树如下:

                a

             /      \

          b          d
         /           /    \

      c           e       f  

                          / 

                       g

结果如下:

 仅此记录,供以后忘记了查阅,同时也希望和大家分享。