最近公共祖先结点 c语言,LCA 最近公共祖先问题 (1)

LCA (Lowest Common Ancestor)

一篇转载的文章,是对于二叉搜索树的算法

http://blog.csdn.net/AmiRural/archive/2006/06/07/777966.aspx

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

int FindLowestCommonAncestor(node *root, int value1, int value2);

shu.bmp

根据树的存储结构,我们可以立刻得到一个这样的算法:从两个给定的结点出发回溯,两条回溯路线的交点就是我们要找的东西。这个算法的具体实现办法是:从根

结点开始,先用这两个结点的全体祖先分别生成两个链表,再把这两个链表第一次出现不同结点的位置找出来,则它们的前一个结点就是我们要找的东西。

这个算法倒没有什么不好的地方,但是它没有利用二元搜索树的任何特征,其他类型的树也可以用这个算法来处理。二元搜索树中左结点的值永远小于或者等于当前

结点的值,而右结点的值永远大于或者等于当前结点的值。仔细研究,4和14的最低公共祖先是8,它与4和14的其他公共祖先是有重要区别的:其他的公共祖

先或者同时大于4和4,或者同时小于4和14,只有8介于4和14之间。利用这一研究成果,我们就能得到一个更好的算法。

从根结点出发,沿着两个给定结点的公共祖先前进。当这两个结点的值同时小于当前结点的值时,沿当前结点的左指针前进;当这两个结点的值同时大于当前结点的

值时,沿当前结点的右指针前进;当第一次遇到当前结点的值介于两个给定的结点值之间的情况时,这个当前结点就是我们要找的最的最低公共祖先了。

这是一道与树有关的试题,算法也有递归的味道,用递归来实现这一解决方案似乎是顺理成章的事,可这里没有这个必要。递归技术特别适合于对树的多个层次进行

遍历或者需要寻找某个特殊结点的场合。这道题只是沿着树结点逐层向下前进,用循环语句来实现有关的过程将更简单明了。

intFindLowestCommonAncestor(node*root,intvalue1,intvalue2)

{

node*curnode=root;while(1)

{if(curnode->data>value1&&curnode->data>value2)

curnode=curnode->left;elseif(curnode->datadata

curnode=curnode->right;elsereturncurnode->data;

}

}

C语言实现:/*二叉排序树的生成及树,任意两结点的最低公共祖先        Amirural设计*/#include#definenull  0intcounter=0;

typedefstructbtreenode

{intdata;structbtreenode*lchild;structbtreenode*rchild;

}bnode;

bnode*creat(intx,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,intx)//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,intx)//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);

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

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

}

}

}intFindLowestCommonAncestor(bnode*root,intvalue1,intvalue2)

{

bnode*curnode=root;while(1)

{if(curnode->data>value1&&curnode->data>value2)

curnode=curnode->lchild;elseif(curnode->datadata

curnode=curnode->rchild;elsereturncurnode->data;

}

}

main()

{

bnode*bt,*p,*q;intx,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(xdata)

q=p->lchild;elseq=p->rchild;

}if(x==p->data)

{printf("元素%d已经插入二叉树中!\n",x);

}elseif(xdata)    ins_lchild(p,x);elseins_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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值