最低公共祖先

转载 2006年06月07日 13:57:00

[题目]:已知二元搜索树(Binary Search Tree)上两个结点的值,请找出它们的公共祖先。你可以假设这两个值肯定存在。这个函数的调用接口如下所示:
      int FindLowestCommonAncestor(node *root, int value1, int value2);

    根据树的存储结构,我们可以立刻得到一个这样的算法:从两个给定的结点出发回溯,两条回溯路线的交点就是我们要找的东西。这个算法的具体实现办法是:从根结点开始,先用这两个结点的全体祖先分别生成两个链表,再把这两个链表第一次出现不同结点的位置找出来,则它们的前一个结点就是我们要找的东西。
    这个算法倒没有什么不好的地方,但是它没有利用二元搜索树的任何特征,其他类型的树也可以用这个算法来处理。二元搜索树中左结点的值永远小于或者等于当前结点的值,而右结点的值永远大于或者等于当前结点的值。仔细研究,4和14的最低公共祖先是8,它与4和14的其他公共祖先是有重要区别的:其他的公共祖先或者同时大于4和4,或者同时小于4和14,只有8介于4和14之间。利用这一研究成果,我们就能得到一个更好的算法。
    从根结点出发,沿着两个给定结点的公共祖先前进。当这两个结点的值同时小于当前结点的值时,沿当前结点的左指针前进;当这两个结点的值同时大于当前结点的值时,沿当前结点的右指针前进;当第一次遇到当前结点的值介于两个给定的结点值之间的情况时,这个当前结点就是我们要找的最的最低公共祖先了。
    这是一道与树有关的试题,算法也有递归的味道,用递归来实现这一解决方案似乎是顺理成章的事,可这里没有这个必要。递归技术特别适合于对树的多个层次进行遍历或者需要寻找某个特殊结点的场合。这道题只是沿着树结点逐层向下前进,用循环语句来实现有关的过程将更简单明了。
     int FindLowestCommonAncestor(node *root, int value1, int value2)
     {
      node *curnode = root;
      while(1)
         {
           if (curnode->data>value1&&curnode->data>value2)
             curnode = curnode->left;
           else if(curnode->data<value1&&curnode->data<value2)
             curnode = curnode->right;
           else
             return curnode->data;
          }
      }

C语言实现:

/*二叉排序树的生成及树,任意两结点的最低公共祖先        Amirural设计*/
#include <stdio.h>
#define  null  0

int counter=0;
typedef struct btreenode
{int data;
 struct btreenode *lchild;
 struct btreenode *rchild;
}bnode;

bnode *creat(int x,bnode *lbt,bnode *rbt)   //生成一棵以x为结点,以lbt和rbt为左右子树的二叉树
{bnode *p;
 p=(bnode*)malloc(sizeof(bnode));
 p->data=x;
 p->lchild=lbt;
 p->rchild=rbt;
 return(p);
}

bnode *ins_lchild(bnode *p, int x)    //x作为左孩子插到二叉树中
{bnode *q;
if(p==null)
  printf("Illegal insert.");
else
 {q=(bnode*)malloc(sizeof(bnode));
  q->data=x;
  q->lchild=null;
  q->rchild=null;
  if(p->lchild!=null)                //若p有左孩子,则将原来的左孩子作为结点x的右孩子
     q->rchild=p->lchild;
  p->lchild=q;
 }
 return(p);
}

bnode *ins_rchild(bnode *p, int x)   //x作为右孩子插入到二叉树
{bnode *q;
 if(p==null)
    printf("Illegal insert.");
 else
 {q=(bnode*)malloc(sizeof(bnode));
  q->data=x;
  q->lchild=null;
  q->rchild=null;
  if(p->rchild!=null)                //若x有右孩子,则将原来的右孩子作为结点x的的左孩子
     q->lchild=p->rchild;
  p->rchild=q;
 }
  return(p);
}

void prorder(bnode *p)
{if(p==null)
   return;
 printf("%d/t%u/t%d/t%u/t%u/n",++counter,p,p->data,p->lchild,p->rchild);
 if(p->lchild!=null)
   prorder(p->lchild);
 if(p->rchild!=null)
   prorder(p->rchild);
}

void print(bnode *p)                //嵌套括号表示二叉树,输出左子树前打印左括号,
{                                   //输出右子树后打印右括号。
  if(p!=null)
  {printf("%d",p->data);
   if(p->lchild!=null||p->rchild!=null)
   {printf("(");
  print(p->lchild);
  if(p->rchild!=null)
   printf(",");
  print(p->rchild);
  printf(")");
 }
}
}

int FindLowestCommonAncestor(bnode *root, int value1, int value2)
{
  bnode *curnode = root;
  while(1)
  {
   if (curnode->data>value1&&curnode->data>value2)
       curnode = curnode->lchild;
   else if(curnode->data<value1&&curnode->data<value2)
       curnode = curnode->rchild;
   else
       return curnode->data;
   }
}

 
main()
{
 bnode *bt,*p,*q;
 int x,y,v1,v2;
 printf("输入根结点:");
 scanf("%d",&x);
 p=creat(x,null,null);
 bt=p;                                   //使bt p都指向根结点
 printf("输入新的结点值:");
 scanf("%d",&x);
 while(x!=-1)
   {p=bt;
    q=p;                    
 while(x!=p->data&&q!=null)              //q记录当前根结点
   {p=q;
    if(x<p->data)
    q=p->lchild;
    else
    q=p->rchild;
   }
  if(x==p->data)
  {printf("元素%d已经插入二叉树中!/n",x);
  }
  else
   if(x<p->data)    ins_lchild(p,x);
      else             ins_rchild(p,x);
   scanf("%d",&x);
   }
 p=bt;
 printf("struct of the binary tree:/n");
 printf("number/taddress/tdata/tlchild/trchild/n");
 prorder(p);
 printf("/n");
 printf("用括号形式输出二叉树:");
 print(p);

 printf("/n请任意输入树中存在的两个结点:");
 scanf("%d,%d",&v1,&v2);
 y = FindLowestCommonAncestor(p, v1, v2);
 printf("输出%d和%d的最低公共祖先:",v1,v2);
 printf("%d/n",y);
}

 运行结果:
输入根结点:20
输入新的结点值:8 22 4 12 10 14 -1       (以-1结束结点的输入)
struct of the binary tree:
number   addresss      data      lchild         rchild
1               4391168       20        4391104   4391040
2               4391104       8          4390976   4399072
3               4390976      4           0                 0
4               4399072     12          4399008  4398944
5               4399008     10          0                0
6               4398644     14          0                0
7               4391040     22          0                0
用括号形式输出:20(8(4,12(10,14)),22)   (输出左子树打印左括号,输出右子树后打印括号)
请任意输入树中存在的两个结点:4,14
输出4和14的最低祖先:8


   

相关文章推荐

[Java]寻找最低公共祖先(排序二叉树)Lowest Common Ancestor of a Binary Search Tree

leetcode 原题链接 https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/ Give...

二叉树中查找两个节点的最低公共祖先

这是一道企业面试中,经常会被问到的面试题目。 在网上看到一些此题的实现,其中有两种方法是比较适合编程的。本项目的源代码,请点击这里下载。 方法一:   此方法是根据二叉树的DFS查找并标记祖先,...
  • fy2462
  • fy2462
  • 2014-06-17 14:24
  • 2007

二叉树两结点最低公共祖先结点(二)

问题 在前面的文章二叉树两结点最低公共祖先结点(一) 中有探讨过这个问题,不过本文考虑的是另外一种二叉树,该二叉树每个结点包含一个指向父结点的指针,根结点的父结点为NULL。其结构如下: ...

【剑指Offer学习】【面试题50:树中两个结点的最低公共祖先】

题目:求树中两个结点的最低公共祖先,此树不是二叉树,并且没有指向父节点的指针。我们首先得到一条从根结点到树中某一结点的路径,这就要求在遍历的时候,有一个辅助内存来保存路径.比如我们用前序遍历的方法来得...

算法:寻找树中两个结点的最低公共祖先

算法:寻找树中两个结点的最低公共祖先

【二叉树】寻找二叉树/BST的两个节点的最低公共祖先

题目:EPI 以下解法要求a,b节点必须在树内。 shared_ptr LCA(const shared_ptr &root, const shared_ptr &a, const sha...

【剑指offer】 面试题50: 树中两个结点的最低公共祖先

题目描述: 给定一棵树,同时给出树中的两个结点,求它们的最低公共祖先。 方法一: 后序遍历   基本思想: 1、两个节点不在一条线上(即两个节点不存在一个节点是另一个...

二叉树求两节点最低公共祖先,求任意两节点距离

-------1.求最低公共祖先LCA( Lowest Common Ancestor )          什么是最低公共祖先?如下图,2与3的LCA是1;1与4的LCA是1;4与5的LCA是2。 ...

寻找二叉树两个节点的最低公共祖先

方法 下面是一个简单的复杂度为 O(n) 的算法,解决LCA问题 1) 找到从根到n1的路径,并存储在一个向量或数组中。 2)找到从根到n2的路径,并存储在一个向量或数组中。 3) 遍历这...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)