映射2分堆转自 http://www.zhongsisi.com/stack-and-mapping/
来源:互联网 发布:安卓电话录音软件 编辑:程序博客网 时间:2024/06/05 18:19
堆与映射
网址: http://www.zhongsisi.com/stack-and-mapping/
引入
这2天都好囧,很久没有写了。今天说说堆与映射。
平常,我们用堆,最常见的就是随机地加入元素,随机地取最大值或最小值。这些基本的操作C++中的priority_queue和set都能很好的完成,而且C++中还有一个make_heap,效率较前面2个会更高。而且前面提到的STL都是采用红黑树实现的,很具有稳定性。
上面的堆虽然使用简单,但功能上还是有些局限。比如前面提到的堆都只能实现删除最值并没有办法删除指定的值。而且一般STL中的堆都是采用数据存储的,但父亲节点和儿子节点需要交换时,我们需要拷贝所存储的整个数据单元,但数据单元较大时,拷贝的效率就低了。因此,这里介绍一中堆变种,在堆中引入了映射。
定义
具有映射功能的堆称为双向映射堆。又其常常是在二分堆的基础上实现的,所以也常常叫映射二分堆。
特点
映射二分堆其与普通堆不同的地方是它的节点并不真正保存数据单元本身,而是保存指向数据单元的指针。因此当需要交换父子节点的数据时,我们可以避免拷贝大量数据所消耗的时间。同时,映射二分堆还有一个功能可以根据具体的数据单元的索引来删除该单元,即使这个单元不是堆中的最值。
实现方法
在实现是,我们可以用数字H[]存储数据单元,然后采用数组ind[i]=j表示H[i]存放的是索引号为j的数据,mp[i]=j表示索引索引为i的元素存储在H[j]中,这样就可以实现双向映射了。
插入堆,我们只需要将插入的元素放在堆尾,然后逐级调整,这个跟普通的二叉堆一样样。
删除最值,也跟普通的二叉堆一样,先把堆中最后一个元素与最值对调,然后在调整堆。
增加一个的是删除固定索引的数据单元,我们可以先通过mp[i],找到其在H[]中存放的位置,然后该位置的值跟堆最后一个元素对调,接着从该节点向上调整堆,此时得到的还不是一个正规的堆,还需要重新堆整个堆进行从上到下调整。
上面的3中操作中都提到了堆的调整,还是上面说的,调整时我们不需要拷贝数据单元,我们只需交换ind[]和mp[]2个数组的对应值即可。
应用
acm题目中,典型可以使用映射堆解决的题目是FOJ 1209 最小权无前缀语言问题,这道题在LRJ的书讲得很详细,但他把这题目命名为最轻巧的语言,在P91。具体的方法我就不多说了,因为LRJ那里已经很具体了。
最后贴一个一个未成型的映射堆的代码,之所以说为成型,是因为这个堆写得不是很清晰,未把映射堆用类封装起来,代码读起来比较辛苦。代码来源dou。代码对应题目是poj 2442 Sequence
#include<stdio.h>
#include<string>
#include<algorithm>
using
namespace
std;
#define N 2010
#define inf 0x7fffffff
int
data1[N], data2[N], data3[N];
int
point[N];
int
heap[N];
struct
node {
int
num;
int
toheap;
} que[N];
int
n;
void
movedown() {
int
i = 1;
int
l, r;
while
(1) {
l = 2 * i;
r = l + 1;
if
(l > n)
break
;
if
(que[heap[i]].num > que[heap[l]].num && ((r <= n && que[heap[l]].num <= que[heap[r]].num) || r > n)) {
swap(que[i].toheap, que[l].toheap);
swap(heap[i], heap[l]);
i = l;
}
else
if
(que[heap[i]].num > que[heap[r]].num && r <= n && que[heap[r]].num <= que[heap[l]].num) {
swap(que[i].toheap, que[r].toheap);
swap(heap[i], heap[r]);
i = r;
}
else
break
;
}
}
int
main() {
int
cas;
int
temp;
scanf
(
"%d"
, &cas);
while
(cas--) {
int
i, j;
int
m;
scanf
(
"%d%d"
, &m, &n);
for
(i = 1; i <= n; ++i)
scanf
(
"%d"
, data1 + i);
sort(data1 + 1, data1 + n + 1);
for
(j = 0; j < m - 1; ++j) {
for
(i = 1; i <= n; ++i)
scanf
(
"%d"
, data2 + i);
sort(data2 + 1, data2 + n + 1);
data2[n + 1] = inf;
for
(i = 1; i <= n; ++i) {
que[i].num = data1[i] + data2[1];
que[i].toheap = i;
heap[i] = i;
point[i] = 1;
}
for
(i = 1; i <= n; ++i) {
data3[i] = que[heap[1]].num;
point[heap[1]]++;
temp = data1[heap[1]] + data2[point[heap[1]]];
que[heap[1]].num = temp;
movedown();
}
memcpy
(data1, data3, 4 * (n + 1));
}
printf
(
"%d"
, data1[1]);
for
(i = 2; i <= n; ++i)
printf
(
" %d"
, data1[i]);
printf
(
"n"
);
}
return
0;
}
- 映射2分堆转自 http://www.zhongsisi.com/stack-and-mapping/
- 转自:http://www.ceo123.com/
- An Overview of Audio and Video Transcoding 转自:http://www.longtailvideo.com/
- Memcache and Mongodb(转自:http://www.cnblogs.com/lovecindywang/archive/2010/05/19/1739025.html)
- argparse解析器 转自http://www.2cto.com/kf/201208/149418.html
- $()和${}和$(())和(())///转自http://www.2cto.com/os/201308/239136.html
- iframe跨域通信方法(转自http://www.2cto.com/kf/201211/166555.html)
- 函数调用约定解析 转载自:http://www.allaboutprogram.com
- JAVA相关基础知识 转自[http://www.blogcn.com]
- [转]数据库连接字符串大全[转自:http://www.connectionstrings.com/]
- 关于render (转自http://www.cnblogs.com/sleeping/)
- 转自http://www.cnblogs.com/flashelf/articles/522348.html
- 中断、DMA、通道(转自http://www.exam100.com/)
- flash xmlsocket policy (安全策略) -- 转自:http://www.diybl.com
- OC4J的使用[转自http://www.suneca.com]
- 正则表达式转自http://www.javaeye.com/topic/30728
- CString 操作指南(转载自http://www.vckbase.com/)
- jquery mobile应用开发--转自http://www.gbin1.com
- android 开发(1)环境的搭建配置
- Top 10 Ways To Dramatically Increase Your Personal Productivivy
- oracle“靠”字的困惑
- 传智播客保证学生就业的六大策略
- hadoop完全分布式设置问题
- 映射2分堆转自 http://www.zhongsisi.com/stack-and-mapping/
- ORACLE批量绑定FORALL与BULK COLLECT
- sql server 2000/2005递归
- C++的XML编程经验――LIBXML2库使用指南
- jquery实现全选/反选
- Linux系统中,main函数的执行过程
- 南山游记(初稿)
- Windows进程通信
- Androd入门知识大总结