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. ANDROID_MARS学习笔记_S01原始版_020_Mp3player001_歌曲列表

    一.项目设计 二.歌曲列表简介 1.利用java.net.HttpURLConnection以流的形式下载xml文件为String 2.自定义ContentHandler-->Mp3ListCo ...

  2. MS提供的虚拟机IE测试

    https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/

  3. xml解析代码示例

    List<Entry> list = new ArrayList<>(); Entry entry = null; try { int eventType = response ...

  4. poj2411Mondriaan's Dream(状压)

    http://poj.org/problem?id=2411 下次还是去学习下dfs的写法吧 自己乱写的好像有点乱 乱七八糟改了一通过了 以1 1 表示横着的 1 0 表示竖着的 枚举每一行的状态 再 ...

  5. POJ_3061_Subsequence_(尺取法)

    描述 http://poj.org/problem?id=3061 给定长度为n的数列整数以及整数S.求出总和不小于S的连续子序列的长度的最小值,如果解不存在输出0. Subsequence Time ...

  6. wildfly-9.0.2 web项目部署详细步骤

    一.配置操作系统环境变量 JAVA_HOME = C:\Program Files (x86)\Java\jdk1.7.0_67 JBOSS_HOME = F:\server\wildfly-9.0. ...

  7. UIScrollView,UIView转换UIImage代码(整个view截图, 不只是可视区域)

    -(UIImage*)captureView:(UIView *)theView{     CGRect rect = theView.frame;     if ([theView isKindOf ...

  8. C#调用C++的DLL函数另一则(delegate) z

    使用DLLImport进行导入函数的事. C#调用C++的函数其实不止这一种方法, 还有一种方法是用delegate申明函数委托进行调用,这种方法略显麻烦,但是可以进行回调并应用指针. 在C#中,首先 ...

  9. From delegates to lambdas z

    I thought of naming this post “Evolution of lambdas in C#”, then I decided that wouldn’t be closest ...

  10. Android之parseSDKContent failed

    由于之前安装ADT之后就一直报parseSDKContent failed的错误,具体的信息为:java.lang.NullPointerException. 此问题的情况为在Eclipse下,And ...