堆(heap) 亦被称为:优先队列(priority queue),是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。在队列中,调度程序反复提取队列中第一个作业并运行,因而实际情况中某些时间较短的任务将等待很长时间才能结束,或者某些不短小,但具有重要性的作业,同样应当具有优先权。堆即为解决此类问题设计的一种数据结构。

本文地址:http://www.cnblogs.com/archimedes/p/binary-heap.html,转载请注明源地址。

逻辑定义

n个元素序列{k1,k2...ki...kn},当且仅当满足下列关系时称之为堆:
(ki <= k2i, ki <= k2i+1)或者(ki >= k2i, ki >= k2i+1),   (i = 1,2,3,4...n/2)

二叉堆一般用数组来表示。如果根节点在数组中的位置是1,第n个位置的子节点分别在2n和 2n+1。因此,第1个位置的子节点在2和3,第2个位置的子节点在4和5。以此类推。这种基于1的数组存储方式便于寻找父节点和子节点。

如果存储数组的下标基于0,那么下标为i的节点的子节点是2i + 1与2i + 2;其父节点的下标是⌊(i − 1) ∕ 2⌋。

如下图的两个堆:

        1               11
/ \ / \
2 3 9 10
/ \ / \ / \ / \
4 5 6 7 5 6 7 8
/ \ / \ / \ / \
8 9 10 11 1 2 3 4

将这两个堆保存在以1开始的数组中:

位置:  1  2  3  4  5  6  7  8  9 10 11
左图: 1 2 3 4 5 6 7 8 9 10 11
右图: 11 9 10 5 6 7 8 1 2 3 4

性质

二叉堆是完全二叉树或者是近似完全二叉树。

二叉堆满足二个特性:

1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。

2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。

当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆

            

最小堆                                                           最大堆

堆支持以下的基本操作:

  • build:建立一个空堆;
  • insert:向堆中插入一个新元素;
  • update:将新元素提升使其符合堆的性质;
  • get:获取当前堆顶元素的值;
  • delete:删除堆顶元素;
  • heapify:使删除堆顶元素的堆再次成为堆。

某些堆实现还支持其他的一些操作,如斐波那契堆支持检查一个堆中是否存在某个元素。

基本操作实现:

1、删除优先级最高的元素(DeleteMin)

此操作分3步:

(1)直接删除根

(2)用最后一个元素代替根

(3)将堆向下重新调整

  输出堆顶元素之后,以堆中最后一个元素替代之;然后将根结点值与左、右子树的根结点值进行比较,并与其中小者进行交换;重复上述操作,直到是叶子结点或其关键字值小于等于左、右子树的关键字的值,将得到新的堆。称这个从堆顶至叶子的调整过程为“筛选”

调整堆算法实现如下:

void down(int p)  /* 调整堆算法 */
{
int q = p * ; /* 向下调整算法,p代表当前结点,q代表子结点 */
a = heap[p]; /* 保存当前结点的值 */
while(q <= hlength) { /* hlength为堆中元素的个数 */
/* 选择两个子节点中的一个最小的 */
if(q < hlength && heap[q] > heap[q + ])
q++;
if(heap[q] >= a) { /* 如果当前结点比子节点小,就结束*/
break;
} else { /* 否则就交换 */
heap[p] = heap[q];
p = q;
q = p * ;
}
}
heap[p] = a; /* 安排原来的结点 */
}

删除最小元素,返回该最小元素:

int DeleteMin()
{
/* 删除最小元素算法 */
int r = heap[]; /* 取出最小元素 */
heap[] = heap[hlength--]; /* 把最后一个叶子结点赋值给根结点 */
down(); /* 调用向下调整算法 */
return r;
}

2、在堆中插入一个新元素Insert(x):

向上调整算法:

void up(int p)
{
/* 向上调整算法,p代表当前结点,q代表父结点 */
int q = p / ; /* 获取当前结点的父结点 */
a = heap[p]; /* 保存当前结点的值 */
while(q >= && a < heap[q]) {
heap[p] = heap[q]; /* 如果当前结点的值比父母结点的值小,就交换 */
p = q;
q = p / ;
}
heap[p] = a; /* 安排原来的结点 */
}

插入元素算法:

void insert(int a)
{
heap[++hlength] = a; /* 先往堆里插入结点值 */
up(hlength); /* 向上调整 */
}

3、将x的优先级上升为p:

void IncreaseKey(int a, int p)  /* 把p的优先级升为a */
{
if(heap[p] < a)
return;
heap[p] = a;
up(p);
}

4、建立堆:

void bulid()  /* 建堆算法 */
{
int i;
for(i = hlength / ; i > ; i--)
down(i); /* 从最后一个非终端结点开始进行调整 */
}

编程实践

poj2051 Argus

http://poj.org/problem?id=2051

#include<stdio.h>
#include<string.h>
char str[];
typedef struct Node {
int now, Q, P;
}Node;
Node node[];
void down(Node H[], int s, int m)
{
int j;
Node rc = H[s];
for(j = s * ; j <= m; j *= ) {
if(j < m) {
if(H[j].now > H[j + ].now) {
j++;
} else {
if((H[j].now == H[j + ].now) && (H[j].Q > H[j + ].Q))
j++;
}
}
if(rc.now < H[j].now || (rc.now == H[j].now && rc.Q < H[j].Q))
break;
H[s] = H[j];
s = j;
}
H[s] = rc;
} void BulidMinHeap(Node H[], int length)
{
int i;
for(i = length / ; i > ; i--)
down(H, i, length);
} void solve()
{
int i, len, K;
i = ;
while(scanf("%s", str) && str[] == 'R') {
scanf("%d %d", &node[i].Q, &node[i].P);
getchar();
node[i].now = node[i].P;
i++;
}
len = i - ;
scanf("%d", &K);
BulidMinHeap(node, len);
for(i = ; i <= K; i++) {
printf("%d\n", node[].Q);
node[].now += node[].P;
down(node, , len);
}
}
int main()
{
solve();
return ;
}

参考资料

1、Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein(潘金贵等译)《算法导论》. 机械工业出版社.

2、Vuillemin, J. (1978). A data structure for manipulating priority queues.Communications of the ACM21, 309–314.

3、ACM/ICPC 算法训练教程

4、《数据结构》严蔚敏、吴伟民

5、维基百科

二叉堆(binary heap)的更多相关文章

  1. 数据结构 之 二叉堆(Heap)

    注:本节主要讨论最大堆(最小堆同理). 一.堆的概念     堆,又称二叉堆.同二叉查找树一样,堆也有两个性质,即结构性和堆序性.     1.结构性质:     堆是一棵被完全填满的二叉树,有可能的 ...

  2. 【数据结构与算法Python版学习笔记】树——利用二叉堆实现优先级队列

    概念 队列有一个重要的变体,叫作优先级队列. 和队列一样,优先级队列从头部移除元素,不过元素的逻辑顺序是由优先级决定的. 优先级最高的元素在最前,优先级最低的元素在最后. 实现优先级队列的经典方法是使 ...

  3. 堆(Heap)和二叉堆(Binary heap)

    堆(Heap) The operations commonly performed with a heap are: create-heap: create an empty heap heapify ...

  4. Binary Heap(二叉堆) - 堆排序

    这篇的主题主要是Heapsort(堆排序),下一篇ADT数据结构随笔再谈谈 - 优先队列(堆). 首先,我们先来了解一点与堆相关的东西.堆可以实现优先队列(Priority Queue),看到队列,我 ...

  5. 二叉堆(binary heap)—— 优先队列的实现

    二叉堆因为对应着一棵完全二叉树,因而可以通过线性数组的方式实现. 注意,数组第 0 个位置上的元素,作为根,还是第 1 个位置上的元素作为根? 本文给出的实现,以数组第 1 个位置上的元素作为根,则其 ...

  6. C# 实现简单的 Heap 堆(二叉堆)

    如题,C#  实现简单的二叉堆的 Push() 和 Pop(), 如有不足欢迎指正. 另外,在C#中使用 Heap 的相似功能可以考虑使用:Priority Queues,SortedDictiona ...

  7. 在A*寻路中使用二叉堆

    接上篇:A*寻路初探 GameDev.net 在A*寻路中使用二叉堆 作者:Patrick Lester(2003年4月11日更新) 译者:Panic 2005年3月28日 译者序 这一篇文章,是&q ...

  8. D&F学数据结构系列——二叉堆

    二叉堆(binary heap) 二叉堆数据结构是一种数组对象,它可以被视为一棵完全二叉树.同二叉查找树一样,堆也有两个性质,即结构性和堆序性.对于数组中任意位置i上的元素,其左儿子在位置2i上,右儿 ...

  9. 二叉堆复习(包括d堆)

    要期中考了……我真的是什么也不会啊,书都没看过TAT. 好吧整理一下二叉堆,这里就以最大堆为例好了. 首先二叉堆其实是一棵CBT,满足父节点的键值大于左右子节点的键值(wikipedia把这个叫键值, ...

随机推荐

  1. SNF开发平台WinForm之三-开发-单表选择控件创建-SNF快速开发平台3.3-Spring.Net.Framework

    3.1运行效果: 3.2开发实现: 3.2.1 这个开发与第一个开发操作步骤是一致的,不同之处就是在生成完代码之后,留下如下圈红程序,其它删除. 第一个开发地址:开发-单表表格编辑管理页面 http: ...

  2. 导出excel和PDF小结 vba

    最近接触了一个关于Access工具的项目,所以整理下需要使用的方法. 功能要求简介: 1.将数据表中的数据导出到excel和PDF 2.并根据某个字段名称分sheet输出. 3.无模板方式 方案简介: ...

  3. C中调用Lua函数

    我们先来看一个简单的例子: lua_State* L = NULL; // 内部调用lua函数 double f(double x, double y) { double z; lua_getglob ...

  4. ef 更新导航属性

    总之,要让所有的东西,都被DbContext管理状态 1.查出来,改了,再提交 2.new 出来,attach,再改,再提交 以上两种都较好理解 3.new出来,改了,再attach,在改状态,再提交 ...

  5. [转载]我们可以用SharePoint做什么

    前言 不知不觉作为一个SharePoint的开发人员若干年了,从SharePoint API开始学习,到了解SharePoint的结构,逐渐一点点了解sharepoint的体系:从SharePoint ...

  6. iOS-Debug调试

    转载:http://www.cnblogs.com/Leo_wl/p/4423922.html

  7. 帮助你在 Photoshop 中轻松实现长阴影效果的工具

    扁平化设计正被用于各个主流的移动操作系统以及许多流行的网站,这是一个不断上升的趋势. 这种趋势有其分支,其中之一是“长阴影 “的效果在元素上的使用. 采用角度为 45 度的投影,给对象添加了一份立体感 ...

  8. 设计模式之Iterator模式(2)

    这篇文章比较简单,作一个笔记. 模拟Iterator. Iterator接口: package cn.asto.Interator; public interface Iterator { publi ...

  9. Res_Orders_01之需求分析

    Res_Orders_01之需求分析 一.背景及好处 为了提高餐厅的运营效率,增强餐厅各部门间的配合,减少顾客到店后的点餐.等餐及结算过程消耗的时间,降低服务员点餐失误率,进一步提高餐厅管理人员对菜品 ...

  10. Ext.NET 4.1.0 GridPanel数据分页

    针对大量数据在前端展示,需要进行分页显示,这里我使用的数据量为100万,数据存储在MongoDb中(也可以存储在本地文件或其它数据库中).最终显示效果如下: 步骤如下: 1.新建程序并配置,详见htt ...