免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12
最近访问板块 发新帖
楼主: lisp
打印 上一主题 下一主题

[算法] 关于在二叉树中求两个节点的最低祖先(lowest ancestor)的算法,请大家多多指教。 [复制链接]

论坛徽章:
0
11 [报告]
发表于 2005-11-17 19:07 |只看该作者
原帖由 lenovo 于 2005-11-17 18:12 发表
分别找到root节点到这两个节点的路径,
最后一个相同的节点就是它们最近的共同祖先。

我觉得这个办法不错

论坛徽章:
0
12 [报告]
发表于 2005-11-17 21:58 |只看该作者
原帖由 lenovo 于 2005-11-17 18:12 发表
分别找到root节点到这两个节点的路径,
最后一个相同的节点就是它们最近的共同祖先。


如果是无序的最坏情况需要遍历整个树将近两次,时间复杂度不是很好

论坛徽章:
0
13 [报告]
发表于 2005-11-18 01:10 |只看该作者
一次bianli就够了...

stack;

travel(tree, pa, pb)
{
if (tree==NULL) return;
if (tree==pa) {
   save_stack_to(stack, pa_stack);
} else if (tree==pb) {
   save_stack_to(stack, pb_stack);
}
if (tree->left != NULL) {
   push(tree->key, stack);
   travel(tree->left, pa, pb);
}
if (tree->right!=NULL) {
   push(tree->key, stack);
   travel(tree->right, pa, pb);
}
pop(stack);
}

diff_stack(pa_stack, pb_stack)
{
// ...
}
比较下pa_stack和pb_stack估计就差不多了

另: 题目不错. 希望LZ多发这种贴子. 增加大家经验zhi.

[ 本帖最后由 yarco2 于 2005-11-18 04:54 编辑 ]

论坛徽章:
0
14 [报告]
发表于 2005-11-18 09:59 |只看该作者
我把大家给出的方法归纳了一下:
win_hate 的第一种方法和lenovo的方法都需要两次遍历二叉树;yarco2将其改进为一次遍历即可。
而win_hate提出的第二种方法空间效率和时间效率都最好,但实现的难度好像很大,写代码很复杂。

论坛徽章:
0
15 [报告]
发表于 2005-11-18 11:12 |只看该作者
我的第二个 proposal 的确不够简洁,但应该还是能实现的。
设计一个主递归函数: double_find (root, a, b, x); 中序遍历一棵树

其返回值 S00, S01, S10, S11 分别表示找不到, 找到了 b, 找到了 a, 找到 a, b
x 为节点指针的指针,如果找到所需的 parent 节点,则存放在 *x 中。 x 也可以换为一个全局变量。

再设计一个 single_find (root, a) 在找到其中一个的情况下找另一个。

代码类似这样

  1. #define S00 0x0;
  2. #define S01 0x1;
  3. #define S10 0x2;
  4. #define S11 0x3;

  5. double_find (root, a, b, x)
  6. {
  7.         int rv, rv2;

  8.         if (root == NULL)
  9.                 return S00;

  10.         if (root == a) {
  11.                 rv = single_find (root->l, b)
  12.                 if (rv == 1) {
  13.                         *x = root;
  14.                         return S11;
  15.                 } else {
  16.                         rv = single_find (root->r, b);
  17.                         if (rv == 1) {
  18.                                 *x = root;
  19.                                 return S11;
  20.                         } else
  21.                                 return  S10;
  22.                 }
  23.         }
  24.        
  25.         if (root == b) {
  26.         ......
  27.         }

  28.         rv = double_find (root->l, a, b, x)
  29.         switch (rv) {
  30.                 case S11:
  31.                         return S11;
  32.                         break;
  33.                 case S10:
  34.                         rv2 = single_find (root->r, b);
  35.                         if (rv2 == 1) {
  36.                                 *x = root;
  37.                                 return S11;
  38.                         } else
  39.                                 return S10;
  40.                         break;
  41.                 case S01:
  42.                         ....
  43.                 case S00:
  44.                         rv2 = double_find (root->r, a, b, x);
  45.                         return rv2;       
  46.                         break;
  47.                 default:
  48.         }
  49.                
  50. }
复制代码


由于并没有写出完整代码,所以无法调试,如果有 bug,请指出。谢谢。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP