阿里巴巴2016年秋季校园招聘C++研发岗在线笔试附加题第一题
2015-08-24 10:45
399 查看
第一次参加在线笔试,没适应节奏,也忘记对题目截图或复制了。下面大概描述一下题目意思:
题目给出了两个结构定义:
struct pair_t {
int a, b;
};
struct node_t {
int a, b;
node_t *left, *right;
};
其中 pair_t 结构表示输入的数据对,node_t 结构表示需要实现的二叉树结构。
1,题目的输入是若干 pair_t 结构的数据,然后要求建立一棵二叉树,要求二叉树的左子树的 a 值小于根节点的 a 值,右子树的 a 值大于根节点的 a 值,且二叉树是一个按 b 值建立的大顶堆。
题目还有个提示:(1)二叉树存在且唯一; (2)先确定根节点。
2,第二问是对于新输入的 pair_t 结构数据,如何插入使其仍然满足该二叉树的性质,因为算法比较复杂,所以只要求给出思路。
(题目大概意思是这样)
我解题的思路:
1,
首先按照 pair_t 结构数据的 a 值排序;
然后根据 pair_t 的 b 值找到根节点;
再根据根节点找到左右子树(pair_t 结构数组中,排序之后,在根节点左边的就是左子树,在右边的就是右子树);
然后重复这一过程即可完成建树。
第一问的代码:
#include <iostream>
using namespace std;
//输入的数据结构
struct pair_t {
int a, b;
};
//二叉树节点结构
struct node_t {
int a, b;
node_t *left, *right;
};
/*
* 因为要求大顶堆的左子树的 a 值小于根节点的 a 值,且右子树的 a 值大于根节点的 a 值,所以按 a 排序;
* 下面是快排函数
*/
void sort_pair_a(pair_t* pair, int start, int end)
{
if(start >= end)
return ;
int begin = start;
int finish = end;
pair_t value;
value = pair[start];
while(start < end) {
for( ; start < end; --end)
if(pair[end].a < value.a) {
pair[start++] = pair[end];
break;
}
for( ; start < end; ++start)
if(pair[start].a > value.a) {
pair[end--] = pair[start];
break;
}
}
pair[start] = value;
sort_pair_a(pair, begin, start);
sort_pair_a(pair, start+1, finish);
}
/*
* 下面是根据数据对的 b 值建大顶堆;
* 试题中其实已经提示大家要先找根节点,所谓根节点,也就是大顶堆的顶,即 b 值最大的数据对;
* 由于通过排序将数据对按 a 的升序排列,所以根据找到的根节点就可以很轻松的确定左右子树了,然后重复这一过程建树;
*
* 按理说对 pair[] 只需要一次排序即可,但是试题只要求写出 build() 函数,所以我这里的快排是放在 build() 函数中的;
* 我在想,其实不排序也可以的,只要先遍历一遍找到根节点,然后再遍历找到左子树和右子树的节点,再建树就可以了;
* 话说回来,排序后理解起来更容易,操作也简单,反正排序函数不难敲对吧 ^.^
*/
node_t* build(pair_t* pair, int n)
{
sort_pair_a(pair, 0, n-1); //对数组 pair 按 a 的值做升序排序。这个排序函数其实可以放在 main() 函数中的,只是题目只要求给出 build() 函数的实现,所以我就放在这里了。
node_t* T = new node_t;
pair_t temp;
temp = pair[0];
int i, loc=0;
//找根节点
for(i=1; i < n; i++)
if(temp.b < pair[i].b) {
temp = pair[i];
loc = i;
}
T->a = temp.a;
T->b = temp.b;
//左子树
if(loc > 0)
T->left = build(pair, loc); //数组pair中的数从位置 0 开始存,所以这里的长度是 loc 而不是 loc-1;
else
T->left = NULL;
//右子树
if(n-loc-1 > 0)
T->right = build(pair+loc+1, n-loc-1); //和上一条语句一样,要注意一下数组起始位置和长度中的 +1 和 -1;
else
T->right = NULL;
return T; //返回根节点
}
//先序遍历
void print_prior(node_t* p)
{
if(p == NULL)
return ;
if(p != NULL)
cout<<"("<<p->a<<", "<<p->b<<") ";//<<endl;
print_prior(p->left);
print_prior(p->right);
}
//中序遍历
void print_mid(node_t* p)
{
if(p == NULL)
return ;
print_mid(p->left);
if(p != NULL)
cout<<"("<<p->a<<", "<<p->b<<") ";//<<endl;
print_mid(p->right);
}
//后序遍历
void print_last(node_t* p)
{
if(p == NULL)
return ;
print_last(p->left);
print_last(p->right);
if(p != NULL)
cout<<"("<<p->a<<", "<<p->b<<") ";//<<endl;
}
#define N 1000
int main()
{
pair_t pair
;
int n;
cin>>n;
for(int i=0; i < n; i++)
cin>>pair[i].a>>pair[i].b;
node_t* T = build(pair, n);
print_prior(T);
cout<<endl;
print_mid(T);
cout<<endl;
print_last(T);
cout<<endl;
return 0;
}
/*
测试样例:
6
5 8
2 10
4 3
1 5
0 2
9 1
*/
2,第二问我之前的思路:
1,首先将要插入的节点的 b 值与根节点的 b 值比较:
1)如果小于根节点的 b 值,转步骤 2;
2)如果大于根节点的 b 值,则将该节点与根节点交换,让它成为新的根节点,然后用原来的根节点作为要插入的节点,重复步骤 1;
2,将该节点的 a 值与根节点的 a 值进行比较:
1)如果小于根节点的 a 值,则将其插入左子树,转步骤 1;
2)如果大于根节点的 a 值,则将其插入右子树,转步骤 1;
//题目已经说明,输入的数据满足要求,二叉树存在且唯一,所以不会存在 a 和 b 值都相等的情况,即不会出现完全一样的节点。
不过后来发现第二问的思路肯定是不对的,因为这个思路可能会破坏 a 值的性质,所以正确的思路应该要先根据 a 值找到合适的位置,然后再进行调整;不过暂时还没完全理清头绪,等确定了再更新。
这里给出第 2 问的错误思路,是告诉和我有过这种思路的同学再思考一下。
上面就是我对该题的理解和解答。这篇博客并非给出标准的答案,只是跟大家交流,如果博客中存在错误,欢迎大家指出,谢谢!
题目给出了两个结构定义:
struct pair_t {
int a, b;
};
struct node_t {
int a, b;
node_t *left, *right;
};
其中 pair_t 结构表示输入的数据对,node_t 结构表示需要实现的二叉树结构。
1,题目的输入是若干 pair_t 结构的数据,然后要求建立一棵二叉树,要求二叉树的左子树的 a 值小于根节点的 a 值,右子树的 a 值大于根节点的 a 值,且二叉树是一个按 b 值建立的大顶堆。
题目还有个提示:(1)二叉树存在且唯一; (2)先确定根节点。
2,第二问是对于新输入的 pair_t 结构数据,如何插入使其仍然满足该二叉树的性质,因为算法比较复杂,所以只要求给出思路。
(题目大概意思是这样)
我解题的思路:
1,
首先按照 pair_t 结构数据的 a 值排序;
然后根据 pair_t 的 b 值找到根节点;
再根据根节点找到左右子树(pair_t 结构数组中,排序之后,在根节点左边的就是左子树,在右边的就是右子树);
然后重复这一过程即可完成建树。
第一问的代码:
#include <iostream>
using namespace std;
//输入的数据结构
struct pair_t {
int a, b;
};
//二叉树节点结构
struct node_t {
int a, b;
node_t *left, *right;
};
/*
* 因为要求大顶堆的左子树的 a 值小于根节点的 a 值,且右子树的 a 值大于根节点的 a 值,所以按 a 排序;
* 下面是快排函数
*/
void sort_pair_a(pair_t* pair, int start, int end)
{
if(start >= end)
return ;
int begin = start;
int finish = end;
pair_t value;
value = pair[start];
while(start < end) {
for( ; start < end; --end)
if(pair[end].a < value.a) {
pair[start++] = pair[end];
break;
}
for( ; start < end; ++start)
if(pair[start].a > value.a) {
pair[end--] = pair[start];
break;
}
}
pair[start] = value;
sort_pair_a(pair, begin, start);
sort_pair_a(pair, start+1, finish);
}
/*
* 下面是根据数据对的 b 值建大顶堆;
* 试题中其实已经提示大家要先找根节点,所谓根节点,也就是大顶堆的顶,即 b 值最大的数据对;
* 由于通过排序将数据对按 a 的升序排列,所以根据找到的根节点就可以很轻松的确定左右子树了,然后重复这一过程建树;
*
* 按理说对 pair[] 只需要一次排序即可,但是试题只要求写出 build() 函数,所以我这里的快排是放在 build() 函数中的;
* 我在想,其实不排序也可以的,只要先遍历一遍找到根节点,然后再遍历找到左子树和右子树的节点,再建树就可以了;
* 话说回来,排序后理解起来更容易,操作也简单,反正排序函数不难敲对吧 ^.^
*/
node_t* build(pair_t* pair, int n)
{
sort_pair_a(pair, 0, n-1); //对数组 pair 按 a 的值做升序排序。这个排序函数其实可以放在 main() 函数中的,只是题目只要求给出 build() 函数的实现,所以我就放在这里了。
node_t* T = new node_t;
pair_t temp;
temp = pair[0];
int i, loc=0;
//找根节点
for(i=1; i < n; i++)
if(temp.b < pair[i].b) {
temp = pair[i];
loc = i;
}
T->a = temp.a;
T->b = temp.b;
//左子树
if(loc > 0)
T->left = build(pair, loc); //数组pair中的数从位置 0 开始存,所以这里的长度是 loc 而不是 loc-1;
else
T->left = NULL;
//右子树
if(n-loc-1 > 0)
T->right = build(pair+loc+1, n-loc-1); //和上一条语句一样,要注意一下数组起始位置和长度中的 +1 和 -1;
else
T->right = NULL;
return T; //返回根节点
}
//先序遍历
void print_prior(node_t* p)
{
if(p == NULL)
return ;
if(p != NULL)
cout<<"("<<p->a<<", "<<p->b<<") ";//<<endl;
print_prior(p->left);
print_prior(p->right);
}
//中序遍历
void print_mid(node_t* p)
{
if(p == NULL)
return ;
print_mid(p->left);
if(p != NULL)
cout<<"("<<p->a<<", "<<p->b<<") ";//<<endl;
print_mid(p->right);
}
//后序遍历
void print_last(node_t* p)
{
if(p == NULL)
return ;
print_last(p->left);
print_last(p->right);
if(p != NULL)
cout<<"("<<p->a<<", "<<p->b<<") ";//<<endl;
}
#define N 1000
int main()
{
pair_t pair
;
int n;
cin>>n;
for(int i=0; i < n; i++)
cin>>pair[i].a>>pair[i].b;
node_t* T = build(pair, n);
print_prior(T);
cout<<endl;
print_mid(T);
cout<<endl;
print_last(T);
cout<<endl;
return 0;
}
/*
测试样例:
6
5 8
2 10
4 3
1 5
0 2
9 1
*/
2,第二问我之前的思路:
1,首先将要插入的节点的 b 值与根节点的 b 值比较:
1)如果小于根节点的 b 值,转步骤 2;
2)如果大于根节点的 b 值,则将该节点与根节点交换,让它成为新的根节点,然后用原来的根节点作为要插入的节点,重复步骤 1;
2,将该节点的 a 值与根节点的 a 值进行比较:
1)如果小于根节点的 a 值,则将其插入左子树,转步骤 1;
2)如果大于根节点的 a 值,则将其插入右子树,转步骤 1;
//题目已经说明,输入的数据满足要求,二叉树存在且唯一,所以不会存在 a 和 b 值都相等的情况,即不会出现完全一样的节点。
不过后来发现第二问的思路肯定是不对的,因为这个思路可能会破坏 a 值的性质,所以正确的思路应该要先根据 a 值找到合适的位置,然后再进行调整;不过暂时还没完全理清头绪,等确定了再更新。
这里给出第 2 问的错误思路,是告诉和我有过这种思路的同学再思考一下。
上面就是我对该题的理解和解答。这篇博客并非给出标准的答案,只是跟大家交流,如果博客中存在错误,欢迎大家指出,谢谢!
相关文章推荐
- 一起talk C栗子吧(第四十一回:C语言实例--哈夫曼树)
- C语言:const关键字、结构体
- C++ 入门教程(一) 写C++前的准备
- 详解C语言中的错误报告errno与其相关应用方法
- c++ 设计模式之简单的工厂模式
- hdu1013-简单模拟
- c++11 mutex ,lock 和 condition_variable 的使用用简介
- C++ 与C
- POJ C++程序设计 编程题#3 编程作业—运算符重载
- 再论C语言指针—对指针的理解
- 开方.cpp
- C语言之位运算
- 《effective C++》:条款37——绝不重新定义继承而来的缺省参数值
- C++中头文件相互包含
- C语言的低级运算
- C++整理1
- C++语言的getline在cl和g++中的不同语义
- C++用多种方式实现Singleton单例模式
- 【C语言】预处理指令—条件编译
- C++: 安装minGW,Msys;对接NeatBeans IDE