careercup-树与图 4.7
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的更多相关文章
- SqlServer-无限递归树状图结构设计和查询
在现实生活中,公司的部门设计会涉及到很多子部门,然后子部门下面又存在子部门,形成类似判断的树状结构,比如说评论楼中楼的评论树状图,职位管理的树状图结构等等,实现类似的树状图数据结构是在开发中经常出现的 ...
- Android开源图表之树状图和饼状图的官方示例的整理
最近由于工作需要,所以就在github上搜了下关于chart的三方框架 官方地址https://github.com/PhilJay/MPAndroidChart 由于工作需要我这里整理了一份Ecli ...
- D3树状图给指定特性的边特别显示颜色
D3作为前端图形显示的利器,功能之强,对底层技术细节要求相对比较多. 有一点,就是要理解其基本的数据和节点的匹配规则架构,即enter,update和exit原理,我前面的D3基础篇中有介绍过,不明白 ...
- D3树状图异步按需加载数据
D3.js这个绘图工具,功能强大不必多说,完全一个Data Driven Document的绘图工具,用户可以按照自己的数据以及希望实现的图形,随心所欲的绘图. 图形绘制,D3默认采用的是异步加载,但 ...
- [整理] ES5 词法约定文档树状图
将ES5 词法说明整理为了树状图,方便查阅,请自行点开小图看大图:
- bzoj 4871: [Shoi2017]摧毁“树状图” [树形DP]
4871: [Shoi2017]摧毁"树状图" 题意:一颗无向树,选两条边不重复的路径,删去选择的点和路径剩下一些cc,求最多cc数. update 5.1 : 刚刚发现bzoj上 ...
- vue 树状图数据的循环 递归循环
在main.js中注册一个子组件 在父组件中引用 树状图的数据格式 绑定一个数据传入子组件,子组件props接收数据 子组件中循环调用组件,就实现了递归循环
- ztree 文件夹类型的 树状图
未套程序的源代码: 链接:http://pan.baidu.com/s/1nuHbxhf 密码:4aw2 已套程序的源代码: css样式: /*发布邮件 选择领导弹窗*/ .xuandao{ disp ...
- visio画等分树状图
一 树状图形状 Search里搜索Tree,找到Double Tree或者Multi Tree的形状 二 分出更多branch 按住主干上的黄色小方块,拖出更多分支. 三 等分分支 将每个分支和对应的 ...
- ArcGIS教程:树状图
摘要 构造可显示特征文件里连续合并类之间的属性距离的树示意图(树状图). 使用方法 · 输入特征文件必须採用预定的特征文件格式. 特征文件可使用 Iso 聚类或创建特征工具来创建.该文件必须至少包括两 ...
随机推荐
- Java泛型反射机制(二)
/** * @author Administrator * 好处:泛型:1安全 2减少代码重用率 */ package com.test; import java.lang.reflect.Metho ...
- 《ArcGIS Engine+C#实例开发教程》第五讲 鹰眼的实现
原文:<ArcGIS Engine+C#实例开发教程>第五讲 鹰眼的实现 摘要:所谓的鹰眼,就是一个缩略地图,上面有一个矩形框,矩形框区域就是当前显示的地图区域,拖动矩形框可以改变当前地图 ...
- ArcGIS Engine Style文件操作
对于一个GISer来说,地图,符号这些都应该有着比别人更深刻的理解和认识,作为平台软件都会提供一套自己的符号库,符号库里面根据类别和种类进行区分,因为点,线,面的自然存在和固有属性是不肯能让你用面状符 ...
- yiic 数据库迁移工具
数据库的结构也同源代码一样随着我们开发的进行而不断的发生着改变.在开发过程中,一般的我们需要像管理我们的源代码一样记录下数据库结构的整个变化过程,以便代码还原到指定版本后,数据库能同步的还原到指定的版 ...
- 《BackboneJS框架的技巧及模式》(4)完结篇
<BackboneJS框架的技巧及模式>(4)完结篇 本文紧接第二部分:<BackboneJS框架的技巧及模式(3)> 作者:chszs,转载需注明.博客主页:http://b ...
- Oracle Developer Form中Block的重新查询
Form中某些按钮可能调用了Package对表中某些字段进行更新,但是数据库中字段的修改不会马上反映到form的界面上,所以要进行重新查询,但是用户可能使用了查询窗口进行查询之后然后再点击按钮动作,如 ...
- linux 内核驱动--Platform Device和Platform_driver注册过程
linux 内核驱动--Platform Device和Platform_driver注册过程 从 Linux 2.6 起引入了一套新的驱动管理和注册机制 :Platform_device 和 Pla ...
- Java通过socket实现smtp协议发送邮件
import java.io.BufferedReader;import java.io.DataOutputStream;import java.io.IOException;import java ...
- 函数 flst_get_first
/********************************************************************//** Gets list first node addre ...
- apache开源项目--kylin
Kylin 是一个开源的分布式的 OLAP 分析引擎,来自 eBay 公司开发,基于 Hadoop 提供 SQL 接口和 OLAP 接口,支持 TB 到 PB 级别的数据量. Kylin 是: 超级快 ...