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[10]= {29,4,6,1,8,3,0,78,23,89};
    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, 0);
    BinarySearchTree*n2 = search(root, 4);
    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 0;
}
时间: 2024-08-27 05:47:41

careercup-树与图 4.7的相关文章

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

D3作为前端图形显示的利器,功能之强,对底层技术细节要求相对比较多. 有一点,就是要理解其基本的数据和节点的匹配规则架构,即enter,update和exit原理,我前面的D3基础篇中有介绍过,不明白的可以再去研究下. 本篇博文,同样是在这个框架下,完成修改树状图中某两个节点之间的边用红色线条连接,实现表达特殊含义的目的. 背景故事: 微信朋友圈之间产品帖子相互转发,有些帖子转发后会有成交,只要有成交,则这个促成成交的节点及其之上的父节点都相应是有功劳的,这个轨迹需要用高亮的颜色表示(比如本例中

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

最近由于工作需要,所以就在github上搜了下关于chart的三方框架 官方地址https://github.com/PhilJay/MPAndroidChart 由于工作需要我这里整理了一份Eclipse版本的类库.(有需要要的留下邮箱) 这就是Code中的效果(树状图) 1 public class BarChartActivity extends Activity implements OnChartValueSelectedListener{ 2 3 private BarChart m

【 D3.js 入门系列 --- 9.5 】 树状图的制作

这一节学习树状图的制作.树状图的制作和集群图完全相同,经过这两种 layout 转换后的数据也很相似. 本人的个人博客为: www.ourd3js.com csdn博客为: blog.csdn.net/lzhlzz 转载请注明出处,谢谢. 树状图( Tree )通常用于表示层级.上下级.包含与被包含关系.树状图的制作和 9.4节集群图的制作 的代码几乎完全一样.不错,你没看错,几乎完全一样.那么为什么要把这两种图分开,它们有什么不同呢?先来看看对于同一组数据,它们的结果有什么不同.数据为: {

bzoj 4871: [Shoi2017]摧毁“树状图”

4871: [Shoi2017]摧毁“树状图” Time Limit: 25 Sec  Memory Limit: 512 MBSubmit: 53  Solved: 9[Submit][Status][Discuss] Description 自从上次神刀手帮助蚯蚓国增添了上千万人口(蚯口?),蚯蚓国发展得越来越繁荣了!最近,他们在地下发现了 一些神奇的纸张,经过仔细研究,居然是D国X市的超级计算机设计图纸!这台计算机叫做‘树状图’,由n个计算 节点与n1条可以双向通信的网线连接而成,所有计算

一款很好用的JQuery dtree树状图插件

一款很好用的JQuery dtree树状图插件 树状图  -dtree 由于他的节点设置思想不错,使连接数据库的数据库设计比较方便. 下载dtree资源包,引用一下dtree.css和dtree.js文件,然后编写节点就行了. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quo

Linux命令之pstree - 以树状图显示进程间的关系

本文链接:http://codingstandards.iteye.com/blog/842156   (转载请注明出处) 用途说明 pstree命令以树状图显示进程间的关系(display a tree of processes).ps命令可以显示当前正在运行的那些进程的信息,但是对于它们之间的关系却显示得不够清晰.在Linux系统中,系统调用fork可以创建子进程,通过子shell也可以创建子进程,Linux系统中进程之间的关系天生就是一棵树,树的根就是进程PID为1的init进程. 常用参

POJ 1436 Horizontally Visible Segments(线段树建图+枚举)

题目连接:http://poj.org/problem?id=1436 题意:给一些线段,每个线段有三个值y1, y2, x代表起点为(x, y1),终点为(x, y2)的线段.当从一个线段可以作水平线到另一个线段并且不穿过其他线段时,就称这两个线段时水平可见的.当三个线段可以两两水平可见,就称为形成一个线段三角.问:在这些线段中有多少个这样的线段三角? 分析:可以把每条线段看做是一个点,如果它和其他线段是水平可见的,就将这两个点相连,由于是无向图,就是你能看到我,我也能看到你,所以需要连接两次

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

D3.js这个绘图工具,功能强大不必多说,完全一个Data Driven Document的绘图工具,用户可以按照自己的数据以及希望实现的图形,随心所欲的绘图. 图形绘制,D3默认采用的是异步加载,但是,这里的异步加载,指的是一次性的将图形展示所需要的数据异步的方式加载到浏览器前端显示.主要有如下这两种方式: 1 d3.csv(url[[, row], callback]) 2 3 Creates a request for the CSV file at the specified url w

[Linux] Linux命令之pstree - 以树状图显示进程间的关系

转载自: http://codingstandards.iteye.com/blog/842156 pstree命令以树状图显示进程间的关系(display a tree of processes).ps命令可以显示当前正在运行的那些进程的信息,但是对于它们之间的关系却显示得不够清晰.在Linux系统中,系统调用fork可以创建子进程,通过子shell也可以创建子进程,Linux系统中进程之间的关系天生就是一棵树,树的根就是进程PID为1的init进程. 常用参数 格式:pstree 以树状图显

ArcGIS教程:树状图

摘要 构造可显示特征文件中连续合并类之间的属性距离的树示意图(树状图). 用法 · 输入特征文件必须采用预定的特征文件格式.特征文件可使用 Iso 聚类或创建特征工具来创建.该文件必须至少包含两个类.可通过扩展名 .gsg 来识别特征文件. · 树状图的输出是一个 ASCII 文本文件.该文件包含两部分:表和图形. 第一部分是以合并顺序显示各类对之间距离的表.第二部分是使用类的 ASCII 字符的图形表达,用来演示合并关系和等级.图形说明了特征文件中合并类对之间的相对距离,这些距离均基于统计得到