4.7 设计并实现一个算法,找出二叉树中某两个结点的第一个共同祖先。不得将额外的结点储存在另外的数据结构中。注意:这不一定是二叉查找树。

解答

本题的关键应当是在Avoid storing additional nodes in a data structure 这句话上。我的理解是,不允许开额外的空间(比如说一个数组)来存储作为中间变量的结点。 虽然我也怀疑它是不是说不允许在结点数据结构Node中加入额外的东西, 比如说父结点的指针。Anyway,我们先从最简单的入手,再一步步加入限制条件。

如果没有任何限制条件,那我觉得最直观的思路就是把其中一个点的所有祖先(包含它自身) 都放入一个哈希表,然后再一步步查找另一个点的祖先结点, 第一个在哈希表中出现的祖先结点即为题目所求。

代码如下,用map模拟(当然,效率比不上哈希表):

算法:

//要使用额外的空间
BinarySearchTree* findFirstAncestor(BinarySearchTree *x,BinarySearchTree *y)
{
if(x==NULL||y==NULL)
return NULL;
map<BinarySearchTree*,bool> mp;
while(x)
{
mp[x]=true;
x=x->parent;
}
while(y)
{
if(mp[y])
return y;
y=y->parent;
}
return y;
}

这里用了一个map来存储中间变量,如果题目不允许开额外的辅助空间,那该如何做呢? 那就老老实实地一个个地试。不断地取出其中一个结点的父结点, 然后判断这个结点是否也为另一个结点的父结点。代码如下:

bool father(BinarySearchTree *x,BinarySearchTree *y)
{
if(x==NULL||y==NULL)
return false;
if(x==y)
return true;
return father(x->left,y)||father(x->right,y);
}
//将每一x的祖先拿出来判断是否为y的祖先,从下到上的方法
BinarySearchTree* find_first_ancestor(BinarySearchTree *x,BinarySearchTree *y)
{
while(x)
{
if(father(x,y))
return x;
x=x->parent;
}
return x;
}

让我们把条件再限制地严苛一些,如果数据结构Node中不允许有指向父亲结点的指针, 那么我们又该如何处理?其实也很简单,首先根结点一定为任意两个结点的共同祖先, 从根结点不断往下找,直到找到最后一个这两结点的共同祖先,即为题目所求。代码如下:

BinarySearchTree* find_ancestor(BinarySearchTree *root,BinarySearchTree *x,BinarySearchTree *y,BinarySearchTree *&ret)
{
if(x==NULL||y==NULL)
return NULL;
if(root&&father(root,x)&&father(root,y))
{
ret=root;
find_ancestor(root->left,x,y,ret);
find_ancestor(root->right,x,y,ret);
}
return ret;
}

这里用到了递归,ans最终保存的是这两个结点从根结点算起最后找到的那个祖先。 因为从根结点开始,每次找到满足要求的结点,ans都会被更新。

C++完整代码:

#include<iostream>
#include<new>
#include<map>
using namespace std; struct BinarySearchTree
{
int elem;
BinarySearchTree *parent;
BinarySearchTree *left;
BinarySearchTree *right;
BinarySearchTree(int x):elem(x),parent(NULL),left(NULL),right(NULL) {}
}; void insert(BinarySearchTree *&root,int z)
{
BinarySearchTree *y=new BinarySearchTree(z);
if(root==NULL)
{
root=y;
return;
}
else if(root->left==NULL&&z<root->elem)
{
root->left=y;
y->parent=root;
return;
}
else if(root->right==NULL&&z>root->elem)
{
root->right=y;
y->parent=root;
return;
}
if(z<root->elem)
insert(root->left,z);
else
insert(root->right,z);
} void createBST(BinarySearchTree *&root)
{
int arr[]= {,,,,,,,,,};
for(auto a:arr)
insert(root,a);
} void inorder(BinarySearchTree *root)
{
if(root)
{
inorder(root->left);
cout<<root->elem<<" ";
inorder(root->right);
}
} BinarySearchTree* findMin(BinarySearchTree *root)
{
if(root==NULL||!root->left)
return root;
while(root->left)
{
root=root->left;
}
return root;
} BinarySearchTree* findMax(BinarySearchTree *root)
{
if(root==NULL||!root->right)
return root;
while(root->right)
{
root=root->right;
}
return root;
} BinarySearchTree* findProcessor(BinarySearchTree* x)
{
if(x->left)
return findMax(x->left);
BinarySearchTree *y=x->parent;
while(y&&y->left==x)
{
x=y;
y=x->parent;
}
return y;
} BinarySearchTree* findSuccessor(BinarySearchTree *x)
{
if(x->right)
return findMin(x->right);
BinarySearchTree *y=x->parent;
while(y&&y->right==x)
{
x=y;
y=x->parent;
}
return y;
}
//要使用额外的空间
BinarySearchTree* findFirstAncestor(BinarySearchTree *x,BinarySearchTree *y)
{
if(x==NULL||y==NULL)
return NULL;
map<BinarySearchTree*,bool> mp;
while(x)
{
mp[x]=true;
x=x->parent;
}
while(y)
{
if(mp[y])
return y;
y=y->parent;
}
return y;
}
bool father(BinarySearchTree *x,BinarySearchTree *y)
{
if(x==NULL||y==NULL)
return false;
if(x==y)
return true;
return father(x->left,y)||father(x->right,y);
}
//将每一x的祖先拿出来判断是否为y的祖先,从下到上的方法
BinarySearchTree* find_first_ancestor(BinarySearchTree *x,BinarySearchTree *y)
{
while(x)
{
if(father(x,y))
return x;
x=x->parent;
}
return x;
}
//从上到下的方法
BinarySearchTree* find_ancestor(BinarySearchTree *root,BinarySearchTree *x,BinarySearchTree *y,BinarySearchTree *&ret)
{
if(x==NULL||y==NULL)
return NULL;
if(root&&father(root,x)&&father(root,y))
{
ret=root;
find_ancestor(root->left,x,y,ret);
find_ancestor(root->right,x,y,ret);
}
return ret;
} BinarySearchTree* search(BinarySearchTree* head, int x)
{
if(head == NULL) return NULL;
if(x == head->elem)
return head;
else if(x <= head->elem)
return search(head->left, x);
else
return search(head->right, x);
}
int main()
{
BinarySearchTree *root=NULL;
createBST(root);
inorder(root);
cout<<endl;
BinarySearchTree *n1 = search(root, );
BinarySearchTree*n2 = search(root, );
cout<<n1->elem<<" "<<n2->elem<<endl;
BinarySearchTree *ans = find_first_ancestor(n1, n2);
cout<<ans->elem<<endl;
BinarySearchTree *ans1 = NULL;
find_ancestor(root, n1, n2, ans1);
cout<<ans1->elem<<endl;
BinarySearchTree *pre=findProcessor(n2);
cout<<pre->elem<<endl;
BinarySearchTree *post=findSuccessor(n2);
cout<<post->elem<<endl;
return ;
}

careercup-树与图 4.7的更多相关文章

  1. SqlServer-无限递归树状图结构设计和查询

    在现实生活中,公司的部门设计会涉及到很多子部门,然后子部门下面又存在子部门,形成类似判断的树状结构,比如说评论楼中楼的评论树状图,职位管理的树状图结构等等,实现类似的树状图数据结构是在开发中经常出现的 ...

  2. Android开源图表之树状图和饼状图的官方示例的整理

    最近由于工作需要,所以就在github上搜了下关于chart的三方框架 官方地址https://github.com/PhilJay/MPAndroidChart 由于工作需要我这里整理了一份Ecli ...

  3. D3树状图给指定特性的边特别显示颜色

    D3作为前端图形显示的利器,功能之强,对底层技术细节要求相对比较多. 有一点,就是要理解其基本的数据和节点的匹配规则架构,即enter,update和exit原理,我前面的D3基础篇中有介绍过,不明白 ...

  4. D3树状图异步按需加载数据

    D3.js这个绘图工具,功能强大不必多说,完全一个Data Driven Document的绘图工具,用户可以按照自己的数据以及希望实现的图形,随心所欲的绘图. 图形绘制,D3默认采用的是异步加载,但 ...

  5. [整理] ES5 词法约定文档树状图

    将ES5 词法说明整理为了树状图,方便查阅,请自行点开小图看大图:

  6. bzoj 4871: [Shoi2017]摧毁“树状图” [树形DP]

    4871: [Shoi2017]摧毁"树状图" 题意:一颗无向树,选两条边不重复的路径,删去选择的点和路径剩下一些cc,求最多cc数. update 5.1 : 刚刚发现bzoj上 ...

  7. vue 树状图数据的循环 递归循环

    在main.js中注册一个子组件 在父组件中引用 树状图的数据格式 绑定一个数据传入子组件,子组件props接收数据 子组件中循环调用组件,就实现了递归循环

  8. ztree 文件夹类型的 树状图

    未套程序的源代码: 链接:http://pan.baidu.com/s/1nuHbxhf 密码:4aw2 已套程序的源代码: css样式: /*发布邮件 选择领导弹窗*/ .xuandao{ disp ...

  9. visio画等分树状图

    一 树状图形状 Search里搜索Tree,找到Double Tree或者Multi Tree的形状 二 分出更多branch 按住主干上的黄色小方块,拖出更多分支. 三 等分分支 将每个分支和对应的 ...

  10. ArcGIS教程:树状图

    摘要 构造可显示特征文件里连续合并类之间的属性距离的树示意图(树状图). 使用方法 · 输入特征文件必须採用预定的特征文件格式. 特征文件可使用 Iso 聚类或创建特征工具来创建.该文件必须至少包括两 ...

随机推荐

  1. 2、RenderScript的计算(2013.05.07)

    一.官方文档翻译: Android Renderscript计算 参考网址: http://blog.csdn.net/fireofstar/article/details/7748143 http: ...

  2. Bex64

    http://speedupcomputercleaner.com/windows-7-error-bex64.php   How To Fix Windows 7 Error Bex64 ? Wha ...

  3. hadoop2.2编程:MRUnit——Test MaxTemperatureMapper

    继承关系1 1. java.lang.Object |__ org.apache.hadoop.mapreduce.JobContext |__org.apache.hadoop.mapreduce. ...

  4. BZOJ_2049_[Sdoi_2008]_Cave_洞穴勘测_(LCT/并查集)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=2049 给出一个森林,起始互不相连,现在有link和cut两种操作,问x,y是否在一棵树里. 分 ...

  5. 五个你可能闻所未闻的出色的Ubuntu替代发行版

      你在使用Ubuntu,可是希望桌面体验……来得更眩目一点.虽说你总是可以添加新的桌面背景,或者索性切换桌面,但是你还有这个选择:换成一种全然不同的发行版. 本文就介绍了五个极其出色的Ubuntu替 ...

  6. oracle的exp、imp命令

    1.EXP a>完全模式 full=y EXP USER/PASSWORD@DB (AS ROLE) BUFFER=64000 FILE=C:\FULL.DMP FULL=Y b>用户模式 ...

  7. 安装qc 出现error An error occurred while attempting to connect to the database.

    When trying to install mercury quality center starter edition 9.0 on Windows XP media center, I am g ...

  8. [codevs1554]最佳课题选择

    题目描述 Matrix67要在下个月交给老师n篇论文,论文的内容可以从m个课题中选择.由于课题数有限,Matrix67不得不重复选择一些课题.完成不同课题的论文所花的时间不同.具体地说,对于某个课题i ...

  9. Xmind Pro 3.4.0.201311050558 Xmind 3.4 破解版 Crack

    其实就一个附件.某大神那里的下不到了.从这里就好了. 使用方法请参见压缩包~ 如果连接不能用了请及时告知回复.>< 仅适用于与版本号为201311050558的Xmind.当然尊重正版开发 ...

  10. Android动态加载so文件

    在Android中调用动态库文件(*.so)都是通过jni的方式,而且往往在apk或jar包中调用so文件时,都要将对应so文件打包进apk或jar包,工程目录下图: 以上方式的存在的问题: 1.缺少 ...