前言

话说新开的博客十分好用...

所以,我打算开一个坑,名曰【算法系列】。

什么意思——从名字泥应该就猜得出来。。。

废话不多说,进入正文~~


正文

原理

首先,堆是一颗二叉树。。

其次,堆是一棵完全二叉树。。

然后,设有一关系 P(Type X, Type Y)

则,堆的每个元素 Element

满足:

foreach Child ∈ Element.Childs do
ASSERT( P(Element.value, Child.value) );

说的明白点,就是每个元素和它的儿子有特定得关系。。。(忽略错别字)

所以,利用堆の性质,我们可以在O(lg n)的时间复杂度内做一些好的事情。。。


解释(?)& 代码

1. 关于堆的存储

设v是堆里一点,则:

v*2 是 v的左儿子

v*2+1 是 v的右儿子

在实际操作中,我们常用位运算加速操作。

即:

inline int LEFT(int x) {return (x<<1);}
inline int RIGHT(int x) {return (x<<1|1);}
inline int FATHER(int x) {return (x>>1);}

2. 初始化堆

heapnum = 0;
memset(heap, 0, sizeof(heap));

3. 维护堆的性质

这是堆比较重要的一个函数。

Heapify(x) 维护以为根的字树保持堆的性质。

代码:

void Heapify(int x){
int largest;
if(LEFT(x) <= heapnum && P(heap[x],heap[LEFT(x)]))
largest = LEFT(x);
else largest = x;
if(RIGHT(x) <= heapnum && P(heap[largest], heap[RIGHT(x)]))
largest = RIGHT(x);
if(largest != x){
Exchange(heap[x], heap[largest]);
Heapify(largest);
}
}

4. UPDATE元素

该函数的作用是把x元素改为y,且必须满足P(heap[x],y)

void HeapInc(int x,int y){
heap[x] = y;
while (x > 1 && P(heap[FATHER(i)], heap[x])) {
Exchange(heap[x], heap[FATHER(x)]);
x = FATHER(x);
}
}

5. 添加元素

不说了。。。上代码:

附注:这里假设P(x,y)表示x<y, 如果P(x,y)表示x>y那么请用INF代替-INF

void HeapAdd(int x){
heap[++heapnum] = -INF;
HeapInc(heapnum, x);
}

6. 关于堆首的操作

首先 --- 返回堆首元素(哈哈,这个不会写的话···)

int Top(){
assert(heapnum >= 1); //assert(x)表示断言,如果x为false就停止程
return heap[1];
}

其次 --- 删除堆首元素

void Pop(){
assert(heapnum >= 1);
Exchange(heap[1], heap[heapnum--]);
if(heapnum) Heapify(1);
}

最后 --- 结合上面两个

int Extract(){
int val = Top();
Pop();
return val;
}

7. 其他一些东西

非空:

bool Empty(){
return heapnum == 0;
}

8. 写成一个类

神马是类?你猜····

const int N                =        30000;
const int HEAPSIZE = N * 4; template <class TElement = int, class Operator = less<int> >
class BasicHeap{
private:
TElement Plc;
TElement heap[HEAPSIZE + 5];
int heapnum;
Operator P;
inline int LEFT(int x){return x<<1;}
inline int RIGHT(int x){return x<<1|1;}
inline int FATHER(int x){return x>>1;}
inline void Exchange(TElement & x, TElement & y){TElement t = x; x = y; y = t;}
void Heapify(int x){
int largest;
if(LEFT(x) <= heapnum && P(heap[x],heap[LEFT(x)]))
largest = LEFT(x);
else largest = x;
if(RIGHT(x) <= heapnum && P(heap[largest], heap[RIGHT(x)]))
largest = RIGHT(x);
if(largest != x){
Exchange(heap[x], heap[largest]);
Heapify(largest);
}
}
inline void Assert(bool flg){
if(!flg){
abort();
}
}
public:
BasicHeap(){
heapnum = 0;
P = Operator();
}
void Inc(int x,int y){
heap[x] = y;
while (x > 1 && P(heap[FATHER(x)], heap[x])) {
Exchange(heap[x], heap[FATHER(x)]);
x = FATHER(x);
}
}
void Add(int y){
heap[++heapnum] = y;
int x = heapnum;
while (x > 1 && P(heap[FATHER(x)], heap[x])) {
Exchange(heap[x], heap[FATHER(x)]);
x = FATHER(x);
}
}
int Top(){
Assert(heapnum >= 1);
return heap[1];
}
void Pop(){
Assert(heapnum >= 1);
Exchange(heap[1], heap[heapnum--]);
if(heapnum) Heapify(1);
}
int Extract(){
int val = Top();
Pop();
return val;
}
void Clear(){
heapnum = 0;
}
bool Empty(){
return heapnum == 0;
}
};
typedef BasicHeap<> MaxHeap;
typedef BasicHeap<int, greater<int> > MinHeap;

算法&数据结构系列 -- 堆(优先队列)的更多相关文章

  1. 图论——Dijkstra+prim算法涉及到的优先队列(二叉堆)

    [0]README 0.1)为什么有这篇文章?因为 Dijkstra算法的优先队列实现 涉及到了一种新的数据结构,即优先队列(二叉堆)的操作需要更改以适应这种新的数据结构,我们暂且吧它定义为Dista ...

  2. 《Algorithms算法》笔记:优先队列(2)——二叉堆

    二叉堆 1 二叉堆的定义 堆是一个完全二叉树结构(除了最底下一层,其他层全是完全平衡的),如果每个结点都大于它的两个孩子,那么这个堆是有序的. 二叉堆是一组能够用堆有序的完全二叉树排序的元素,并在数组 ...

  3. 纯数据结构Java实现(6/11)(二叉堆&优先队列)

    堆其实也是树结构(或者说基于树结构),一般可以用堆实现优先队列. 二叉堆 堆可以用于实现其他高层数据结构,比如优先队列 而要实现一个堆,可以借助二叉树,其实现称为: 二叉堆 (使用二叉树表示的堆). ...

  4. 数据结构与算法入门系列教程-C#

    数据结构与算法入门系列教程 (一)为啥要学习数据结构与算法 曾经我也以为自己很牛逼,工作中同事也觉得我还可以,领导也看得起我,啥啥啥都好,就这样过了几年,忽然发现自己学新东西没劲.时代都变了,而我还只 ...

  5. 经典算法研究系列:二、Dijkstra 算法初探

    July   二零一一年一月 本文主要参考:算法导论 第二版.维基百科. 一.Dijkstra 算法的介绍 Dijkstra 算法,又叫迪科斯彻算法(Dijkstra),算法解决的是有向图中单个源点到 ...

  6. 【JavaScript数据结构系列】00-开篇

    [JavaScript数据结构系列]00-开篇 码路工人 CoderMonkey 转载请注明作者与出处 ## 0. 开篇[JavaScript数据结构与算法] 大的计划,写以下两部分: 1[JavaS ...

  7. 经典面试题(二)附答案 算法+数据结构+代码 微软Microsoft、谷歌Google、百度、腾讯

    1.正整数序列Q中的每个元素都至少能被正整数a和b中的一个整除,现给定a和b,需要计算出Q中的前几项, 例如,当a=3,b=5,N=6时,序列为3,5,6,9,10,12 (1).设计一个函数void ...

  8. 【C#数据结构系列】查找

    一:查找 1.1 基本概念和术语 查找(Search)是在数据结构中确定是否存在关键码等于给定关键码的记录的过程.关键码有主关键码和次关键码.主关键码能够唯一区分各个不同的记录,次关键码通常不能唯一区 ...

  9. 【JavaScript数据结构系列】03-队列Queue

    [JavaScript数据结构系列]03-队列Queue 码路工人 CoderMonkey 转载请注明作者与出处 1. 认识队列Queue结构 队列,跟我们的日常生活非常贴近,我们前面举例了食堂排队打 ...

随机推荐

  1. bat判断当前目录是否是根目录

    记录下,一遍查用. @echo offif "%~p0"=="\" (echo 在根目录) else echo 不在根目录pause

  2. mysql中使用show table status 查看表信息

    本文导读:在使用mysql数据库时,经常需要对mysql进行维护,查询每个库.每个表的具体使用情况,Mysql数据库可以通过执行SHOW TABLE STATUS命令来获取每个数据表的信息. 一.使用 ...

  3. putty 与winscp 区别

    https://zhidao.baidu.com/question/377968180.html putty 与winscp 有什么区别, 装了 winscp 可以由 putty 替换么 ? 具体用法 ...

  4. 注解Responsebody RequestBody RequestMapping

    编写代码时候很容易遗漏注解,尤其比较重要的注解,调试很久也找不到原因,在处理页面请求异常时,如果后台正常,就是发现没有把想要的对象传到页面就注意下看注解是否缺失?例如:/** * @Author gj ...

  5. Flexible Box布局基础知识详解

    1.基本概念,借用阮一峰老师的一张图: 容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis).主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫 ...

  6. 2.supervisor实时监控程序存活状态

    1.supervisor是一款python开发的一个client/server服务,是一款进程管理工具,支持linux/unix系统,但是不支持windows系统. 它可以很方便的监听.启动.停止.重 ...

  7. ASP.NET没有魔法——ASP.NET MVC 模型绑定

    在My Blog中已经有了文章管理功能,可以发布和修改文章,但是对于文章内容来说,这里缺少最重要的排版功能,如果没有排版的博客很大程度上是无法阅读的,由于文章是通过浏览器查看的,所以文章的排版其实与网 ...

  8. cpp - 编译过程

    预处理 E:\CppSpace\hello>g++ -o main.i -E main.cpp E:\CppSpace\hello>dir /p 驱动器 E 中的卷是 固盘-项目 卷的序列 ...

  9. vim编辑操作

    vim    插入模式        a    光标后        A    行尾        o    光标所在行下一行        O    光标所在行上一行        i    光标前 ...

  10. JavaScript return 最简单解释

    一.return 返回值 1)函数名字 +括号 :fun() ==> retrun 后面的值 2)所以函数的模范返回值是为未定义 3)return; 后面的任何代码都不会执行了 二.arguem ...