整数对A满足二叉查找树,B满足最大堆
1 题目
给出一组整数对 { (a[0], b[0]), (a[1], b[1]) ... (a[n-1], b[n-1]) },全部 a 值和 b 值分别不反复(随意 i != j 满足 a[i] != a[j] 且 b[i] != b[j])。
构造一棵 n 结点的二叉树,将这 n 个整数对分配到各个结点上。根和全部子树满足下面条件:1) 全部结点的 a 值满足二叉查找树的顺序。即 left->a <root->a && root->a < right->a。2) 全部结点的 b 值满足最大堆的顺序。即 root->b
>left->b && root->b > right->b。
问题一:实现 build 函数,输入 n 个整数对。返回一棵构造好的二叉树。
struct pair_t { int a,b;};struct node_t { int a, b; node_t *left, *right;};node_t*build(pair_t* pair, int n);
问题二:已知满足上述条件的二叉树,设计算法实现插入一个整对 (a, b),使新的二叉树仍满足上述条件。该算法比較复杂。候选人仅仅需描写叙述思路。
若有错误欢迎大家指正,若有更好的方法。欢迎大家不吝赐教!
2 分析
该问题的关键就是找树根。
方法一:当前全部整数对的树根为b中最大值相应的整数对I。由于仅仅有这样才干满足最大堆的性质。然后依据I中的a值将整数对分为比a大于比a小两组,小的作为左子树,大的作为右子树。当整数对个数为0时,返回NULL。该方法时间复杂度O(n2)。
方法二(华南理工大神ohm提供):将整数对依照b进行逆向排序,然后依照a进行二分叉树的插入操作就可以。
该方法的时间复杂度为O(nlogn)。
3 实现
方法一实现:
struct pair_t
{
int a, b;
}; struct node_t
{
int a, b;
node_t *left, *right;
}; node_t *build(pair_t *pair, int n);
int findMaxB(pair_t *pair, int n); int findMaxB(pair_t *pair, int n)
{
int pos = 0; for (int i = 1; i < n; ++i)
{
if (pair[pos].b < pair[i].b)
{
pos = i;
}
} return pos;
} node_t *build(pair_t *pair, int n)
{
if (0 == n)
{
return NULL;
}
node_t *root = new node_t[1];
pair_t *pair1 = new pair_t[n];
pair_t *pair2 = new pair_t[n];
int num1 = 0;
int num2 = 0;
int maxB = findMaxB(pair, n);
root->a = pair[maxB].a;
root->b = pair[maxB].b;
int maxBA = pair[maxB].a;
for (int i = 0; i < maxB; ++i)
{
if (pair[i].a < maxBA)
{
pair1[num1].a = pair[i].a;
pair1[num1++].b = pair[i].b;
}
else
{
pair2[num2].a = pair[i].a;
pair2[num2++].b = pair[i].b;
}
}
for (int i = maxB + 1; i < n; ++i)
{
if (pair[i].a < maxBA)
{
pair1[num1].a = pair[i].a;
pair1[num1++].b = pair[i].b;
}
else
{
pair2[num2].a = pair[i].a;
pair2[num2++].b = pair[i].b;
}
}
root->left = build(pair1, num1);
delete []pair1; root->right = build(pair2, num2);
delete []pair2;
return root;
}
方法二实现:
void insert(node_t *&root, pair_t p)
{
if (root == NULL)
{
root = new node_t;
root->a = p.a;
root->b = p.b;
root->left = NULL;
root->right = NULL;
return;
}
if (root->a < p.a)
{
insert(root->right, p);
}
else
{
insert(root->left, p);
}
} node_t *build(pair_t *pair, int n)
{
if (0 == n)
{
return NULL;
}
node_t *root = NULL;
sort(pair, pair + n);
for (int i = 0; i < n; ++i)
{
insert(root, pair[i]);
}
return root;
}
4 问题二
设插入整数对为(nA, nB),当前訪问树中结点为curNode。插入步骤例如以下:
(1) 若curNode.b>nB。则比較curNode.a与nA。若curNode.a>nA,则curNode=curNode->left;反之,curNode=curNode->right。直到curNode.b<nB或curNode=NULL,停止查找。
(2) 若curNode=NULL,则直接将该整数对插入到此位置就可以;反之,将(nA,nB)作为curNode父结点的孩子结点。curNode作为插入结点的孩子结点(依据a的值确定是左孩子还是右孩子)。
(3) curNode作为新插入结点的右(左)孩子。则须要遍历curNode的左(右)子树,找到a值小于nA的子树的根作为新插入结点的左(右)孩子。当然若不存在时先插入结点不存在左(右)孩子。
整数对A满足二叉查找树,B满足最大堆的更多相关文章
- 由后序遍历结果构造二叉查找树 && 二叉查找树链表化
二叉查找树通俗说就是左孩子比父亲小,右孩子比父亲大.构造这么一个树,树嘛,递归即可. 例如一棵树后序遍历是这样(下图的树):2 9 8 16 15 10 25 38 45 42 30 20.最后的20 ...
- java实现二叉树的建立以及实现二叉查找树的查、插、删、遍历
一.采用存储结构 1.顺序存储:采用数组,顺序存储适配于完全二叉树,对于非完全二叉树并不合适,主要体现在空间上的浪费,所以我们需要用到另一种存储方式——链式存储. 2.链式存储:数据data用键值对的 ...
- 二叉查找树迭代器 · Binary Search Tree Iterator
[抄题]: 设计实现一个带有下列属性的二叉查找树的迭代器: 元素按照递增的顺序被访问(比如中序遍历) next()和hasNext()的询问操作要求均摊时间复杂度是O(1) 对于下列二叉查找树,使用迭 ...
- 剑指offer23:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。输出Yes OR No。
1 题目描述 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. 2 思路和方法 二叉搜索树:二叉查找树(Bin ...
- 从二叉查找树到平衡树:avl, 2-3树,左倾红黑树(含实现代码),传统红黑树
参考:自平衡二叉查找树 ,红黑树, 算法:理解红黑树 (英文pdf:红黑树) 目录 自平衡二叉树介绍 avl树 2-3树 LLRBT(Left-leaning red-black tree左倾红黑树 ...
- 常见基本数据结构——树,二叉树,二叉查找树,AVL树
常见数据结构——树 处理大量的数据时,链表的线性时间太慢了,不宜使用.在树的数据结构中,其大部分的运行时间平均为O(logN).并且通过对树结构的修改,我们能够保证它的最坏情形下上述的时间界. 树的定 ...
- 找出 int 数组的平衡点 & 二叉树 / 平衡二叉树 / 满二叉树 / 完全二叉树 / 二叉查找树
找出 int 数组的平衡点 左右两边和相等, 若存在返回平衡点的值(可能由多个); 若不存在返回 -1; ``java int [] arr = {2,3,4,2,4}; ```js const ar ...
- C语言 · 查找整数 · 基础练习
问题描述 给出一个包含n个整数的数列,问整数a在数列中的第一次出现是第几个. 输入格式 第一行包含一个整数n. 第二行包含n个非负整数,为给定的数列,数列中的每个数都不大于10000. 第三行包含一个 ...
- C语言 · 整数平均值
编写函数,求包含n个元素的整数数组中元素的平均值.要求在函数内部使用指针操纵数组元素,其中n个整数从键盘输入,输出为其平均值. 样例输入: (输入格式说明:5为输入数据的个数,3 4 0 0 2 是以 ...
随机推荐
- ARM DEBUGGER FOR NEARLY ONE DOLLAR
http://hackaday.com/2014/01/23/arm-debugger-for-nearly-one-dollar/ Oh that title is so misleading. B ...
- STM32F4: Generating parallel signals with the FSMC
STM32F4: Generating parallel signals with the FSMC The goal: The memory controller can be used to ge ...
- 北大 ACM 分类 汇总
1.搜索 //回溯 2.DP(动态规划) 3.贪心 北大ACM题分类2009-01-27 1 4.图论 //Dijkstra.最小生成树.网络流 5.数论 //解模线性方程 6.计算几何 //凸壳.同 ...
- 改进架构,实现动态数据源,减少java维护
怎样不用写java代码来完毕开发? 对于大部分的产品和项目来说.页面变化是很头痛的事情.每次小功能上线,新客户到来,都须要进行定制改造,不断的开发维护.每次开发一方面要修改页面,一方面要修改serve ...
- asp.net core读取appsettings.json,如何读取多环境开发配置
摘要 在读取appsettings.json文件中配置的时候,觉得最简单的方式就是使用asp.net core注入的方式进行读取了. 步骤 首先根据配置项的结构定义一个配置类,比如叫AppSettin ...
- 使用FTP发布和更新Windows Azure网站
在Windows Azure中,FTP的用户名和密码与管理门户的用户名和密码不一样,需要另外设置. →依次点击左侧的"网站",网站名称,右侧的"设置部署凭据", ...
- ASP.NET MVC中实现属性和属性值的组合,即笛卡尔乘积02, 在界面实现
在"ASP.NET MVC中实现属性和属性值的组合,即笛卡尔乘积01, 在控制台实现"中,在控制台应用程序中实现了属性值的笛卡尔乘积.本篇在界面中实现.需要实现的大致如下: 在界面 ...
- iOS-Xcode必备插件XAlign:瞬间优化你的代码
今天向大家介绍一个非常好用的Xcode代码编辑插件,这个插件可以很快速地使代码对齐,有3种模式:“=”对齐.宏定义对齐和属性对齐 XAlign效果图 1.“=”对齐 2.宏定义对齐 3.属 ...
- 【java】ThreadLocal线程变量的实现原理和使用场景
一.ThreadLocal线程变量的实现原理 1.ThreadLocal核心方法有这个几个 get().set(value).remove() 2.实现原理 ThreadLocal在每个线程都会创建一 ...
- Android之sqlite3命令行简单使用
首先需要定位到database所在的目录里面,然后使用命令 sqlite3 databasename(数据库的名字)进入 常用命令: 1. .table 列取该数据库下面的数据表名 2. .s ...