整数对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的子树的根作为新插入结点的左(右)孩子。当然若不存在时先插入结点不存在左(右)孩子。

时间: 2024-10-05 02:36:34

整数对A满足二叉查找树,B满足最大堆的相关文章

[二叉查找树] 二叉排序树

题目描述 输入一系列整数,建立二叉排序数,并进行前序,中序,后序遍历. 输入 输入第一行包括一个整数n(1<=n<=100).接下来的一行包括n个整数. 输出 可能有多组测试数据,对于每组数据,将题目所给数据建立一个二叉排序树,并对二叉排序树进行前序.中序和后序遍历.每种遍历结果输出一行.每行最后一个数据之后有一个空格. 样例输入 1 2 2 8 15 4 21 10 5 39 样例输出 2 2 2 8 15 8 15 15 8 21 10 5 39 5 10 21 39 5 10 39 21

由后序遍历结果构造二叉查找树

二叉查找树通俗说就是左孩子比父亲小,右孩子比父亲大.构造这么一个树,树嘛,递归即可. 例如一棵树后序遍历是这样(下图的树):2 9 8 16 15 10 25 38 42 45 30 20.最后的20肯定是树根,这里要抓住一个规律:20是树根,那么2 9 8 16 15 10都是左子树,25 38 42 45 30在右子树,因为左边都小于根.右边都大于根嘛.然后递归即可. 下面是树的样子和代码和src.txt(后序遍历的结果)以及运行结果: 1 #include <iostream> 2 #i

二叉排序树(二叉查找树)

参考:http://student.zjzk.cn/course_ware/data_structure/web/chazhao/chazhao9.3.1.1.htm 1 #include "stdafx.h" 2 #include <iostream> 3 4 typedef int InfoType; //其它数据域,自定义 5 typedef int KeyType; //假定关键字类型为整数 6 typedef struct node //结点类型 7 { 8 Ke

C语言强化(八)判断序列是不是二叉查找树的后序遍历结果

前面聊了一系列关于链表相交的问题,本篇博文,让我们通过一道简单的判断题,复习复习数组和二叉树. 通过这道题,你可以掌握 二叉查找树的规律 后序遍历的特点 递归的使用 题目 输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果. 如果是返回 true,否则返回 false. 例如输入 5.7.6.9.11.10.8,由于这一整数序列是如下树的后序遍历结果: 因此返回 true. 如果输入 7.4.6.5,没有哪棵树的后序遍历的结果是这个序列,因此返回 false. 看到二元查找树(or二

第9题:判断整数序列是不是二元查找树的后序遍历结果

欢迎转载,转载请务必注明出处:http://blog.csdn.net/alading2009/article/details/44872143 第9题:输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果.如果是返回true,否则返回false. 例如输入5.7.6.9.11.10.8,由于这一整数序列是如下树的后序遍历结果: 因此返回true. 如果输入7.4.6.5,没有哪棵树的后序遍历的结果是这个序列,因此返回false. 由于二叉查找树的特性(左子树的值小于根节点,右子树的值

C/C++算法竞赛入门经典Page11 例题1-5 三整数排序

题目:输入3个整数,从小到大排序后输出 样例输入: 20 7 33 样例输出: 7 20 33 首先,先声明三个整数a,b,c和一个临时变量t: int a,b,c,t;//1,b,c为三个整数,t为临时变量 输入三个整数: scanf("%d%d%d",&a,&b,&c); 进行3次if判断: 1.如果b>a,则a,b对调 2.如果c>a,则a,c对调 3.如果c>b,则b,c对调 代码: if(b>=a){ t=b; b=a; a=t

【BZOJ4942】[Noi2017]整数 线段树+DFS(卡过)

[BZOJ4942][Noi2017]整数 题目描述去uoj 题解:如果只有加法,那么直接暴力即可...(因为1的数量最多nlogn个) 先考虑加法,比较显然的做法就是将A二进制分解成log位,然后依次更新这log位,如果最高位依然有进位,那么找到最高位后面的第一个0,将中间的所有1变成0,那个0变成1.这个显然要用到线段树,但是复杂度是nlog2n的,肯定过不去. 于是我在考场上yy了一下,这log位是连续的,我们每次都要花费log的时间去修改一个岂不是很浪费?我们可以先在线段树上找到这段区间

判断给定十进制整数的二进制形式中含有几个1

两种判断一个给定整数的二进制形式中含有几个1的简单方法: 主要思想是通过按位与(&)运算和位移运算(<< >>)实现 1 unsigned int_number( int n) 2 { 3 if (n < 0) 4 return; 5 unsigned count = 0; 6 while (n != 0) 7 { 8 if ((n & 1) != 0) 9 ++count; 10 n >>= 1; 11 } 12 return count; 13

2_C语言中的数据类型 (三)整数与无符号数

1.1       sizeof关键字 sizeof是c语言关键字,功能是求指定数据类型在内存中的大小,单位:字节 sizeof与size_t类型 1.1       int类型 1.1.1          int常量,变量 int就是32位的一个二进制整数,在内存当中占据4个字节的空间 1.1.2          printf输出int值 %d,输出一个有符号的10进制整数,%u,代表输出一个无符号的十进制整数 1.1.3          printf输出八进制和十六进制 %x,代表输出