《数据结构》C++代码 堆(优先队列)

       堆,是优先队列最常用的一种实现方式。在优先队列中,每个元素都被赋予了一个优先级,而每次出队时都让优先级最高的元素出队。堆,则是一种存储优先队列的方法,特指以一棵树形式存储的优先队列。最常用的是二叉堆,但既然是专门介绍数据结构,就不妨说全一些,我们取4个典型的堆进行比较,见下表(此表及表下备注,来自于广东省中山市第一中学黄源河前辈的《左偏树的特点及其应用》,并做过言辞修改及内容补充):

项目


二叉堆


左偏树


二项堆


Fibonacci堆


构建


O(n)


O(n)


O(n)


O(n)


插入


O(logn)


O(logn)


O(logn)


O(1)


取最小点


O(1)


O(1)


O(logn)


O(1)


删除最小点


O(logn)


O(logn)


O(logn)


O(logn)


删除任意点


O(logn)


O(logn)


O(logn)


O(logn)


合并


O(n)


O(logn)


O(logn)


O(1)


空间需求


最小


较小


一般


较大


编程复杂度


最低


较低


较高


很高

       在此说明几点:

0、二项堆又称Bernoulli堆,左偏树又称左堆;斜堆并未在表中列出,是由于其复杂度与左偏树相同,没必要单独列出。其代码更简单,但常数较大,且在特殊数据下可能退化成O(n)。它与左偏树的关系,就像Splay与AVL的关系,并无优劣之分,前者更简洁灵活而后者更快。另外,我并未谈及D堆,那是因为这类仅在接触外存才值得应用的堆,我并不想提及。大家在考试用不上,平时也用不上,故而在我看来暂时了解、理解就好,之后真正用到了再去深究不迟。

1、二项堆,其“取最小点”的复杂度是O(log n),可以改进为O(1)。方法是,随时记录最小节点,并只在插入、删除以及合并等操作进行的时候更新该记录。

2、二项堆,其“插入”操作的平均时间复杂度为O(1),表中给出的是最坏时间复杂度。

3、Fibonacci堆,其“删除最小点”和“删除任意点”两个操作的时间复杂度均为平摊时间复杂度。

       可能大家并未了解全,那就请自行搜索吧,我在此仅仅给出实现代码。由于种类过多,我仅仅对每种堆给出一种最常见的实现方式(例如二叉堆仅仅给出数组实现法),大家视题目需要而融会贯通即可。另外,由于代码较长,为了方便大家比较,我仅仅给出类版,实际实现时,不写成类有时反而方便许多。

       还有,我依旧假设每个元素的信息仅有一个int权值,这样可以让大家更关注代码的框架结构,而不至于在繁琐的代码中看得迷迷糊糊。真正使用时,如果元素信息增多,视情况修改即可。

代码:

// 本代码所实现的是最小堆
const int maxk = 10;
const int maxn = 1024;
inline swap(int &x,int &y) { int t=x; x=y; y=t; }

// 二叉堆
// 实现了init、in、out操作
class Two_Heap
{
    int H[maxn+1],L; // H[1~L]是堆中元素
    void up(int i)
    {
        int j=i>>1;
        if(i==1) return;
        if(H[i]>=H[j]) return;
        swap(H[i],H[j]); up(j);
    }
    void down(int i)
    {
        int j=i<<1;
        if(j>L) return;
        if(j!=L && H[j+1]<H[j]) ++j;
        if(H[i]<=H[j]) return;
        swap(H[i],H[j]); down(j);
    }
public:
    Two_Heap():L(0) {}
    void init(int A[],int N)
    {
        // 以一个数组A[1~N]去初始化堆,这是堆排中建堆的过程,复杂度O(N)
        L=N;
        for(int i=1;i<=N;++i) H[i]=A[i];
        for(int i=N>>1;i>=1;--i) down(i); // 可以证明,从N/2开始调整即可,后N/2个点必然是叶子结点
    }
    void in(int x) { A[++L]=x; up(L); }
    int out() { swap(A[1],A[L--]); down(1); return A[L+1]; }
    int min() { return A[1]; }
};

// 未完待续

时间: 2024-10-07 15:57:52

《数据结构》C++代码 堆(优先队列)的相关文章

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

堆其实也是树结构(或者说基于树结构),一般可以用堆实现优先队列. 二叉堆 堆可以用于实现其他高层数据结构,比如优先队列 而要实现一个堆,可以借助二叉树,其实现称为: 二叉堆 (使用二叉树表示的堆). 但是二叉堆,需要满足一些特殊性质: 其一.二叉堆一定是一棵完全二叉树 (完全二叉树可以用数组表示,见下面) 完全二叉树缺失的部分一定是在右下方.(每层一定是从左到右的顺序优先存放) 完全二叉树的结构,可以简单理解成按层安放元素的.(所以数组是不错的底层实现) 其二.父节点一定比子节点大 (针对大顶堆

数据结构之基于堆的优先队列

优先队列的最重要的操作:删除最大元素(或最小)和插入元素.数据结构二叉堆能够很好的实现队列的基本操作.二叉堆的结点按照层级顺序放入数组,用长度为N+1的私有数组pq来表示一个大小为N的堆(堆元素放在pq[1]至pq[N]之间,为方便计数,未使用pq[0]),跟节点在位置1,它的子结点在位置2和3,以此类推.位置k的节点的父节点位置为k/2,它的两个子节点位置分别为2k和2k+1.当一颗二叉树的每个节点都大于等于它的两个子节点时,称为大根堆.当一颗二叉树的每个节点都小于等于它的两个子节点时,称为小

堆-优先队列

堆-优先队列 前置知识:二叉树. 参考资料 暂无 堆就是优先队列,可以用来解决动态区间查询最值问题. 堆就是一个完全二叉树,可以插入节点,删除根节点(也可以删除特定节点). 为了方便,普通的堆节点 \(i\) 的父亲就是 \([i\div2]\) (\([x]\) 表示不超过 \(x\) 的最大整数). 节点 \(i\) 的左儿子是 \(i\times2\),右儿子是 \(i\times2+1\). 对于一个大顶堆: 每次插入节点的时候,就把节点插在完全二叉树的最后,如果它比它的父亲节点大,就把

[数据结构学习备忘录]堆及其堆排序

[数据结构学习备忘录] 堆 一种数据结构,物理存储方式:数组 逻辑存储方式:近似于完全二叉树,假定i为堆元素的序数[Index],那么i/2就是该元素的左子树,(i/2 + 1)就是该元素的右子树,分为两种堆:大根堆.小根堆:这两种堆的区别是:大根堆的根节点元素的值比左右子树的值都要大,小根堆则相反. 可用这种数据结构进行排序,称为堆排序. 与该数据结构相关的关键算法: ①   MaxHeaplfy 当堆的元素顺序出现错误时的调整函数 ②   BulidMax[min]Heap 建立大[小]根堆

数据结构—串的堆分配

#include<stdio.h> #include<stdlib.h> typedef struct { char *ch; int length; }HString; void StrAssign(HString &T,char *chars); void StrLength(HString S); void StrCompare(HString S,HString T); void ClearString(HString &S); void Concat(HS

堆 (优先队列)举例

*/--> pre.src {background-color: Black; color: White;} 堆 (优先队列)举例 题目: 你需要驾驶一辆卡车行驶 l 单位距离.最开始的时候,卡车上有 p 单位的汽油.卡车每开 1 单位距离需要消费 1 单位的汽油.如果在途中汽车上的汽油耗尽,卡车就无法继续前行,因而无法到达终点.在途中一共有 n 个加油站.第 i 个加油站在距离起点 ai 单位距离的地方,最多可以给卡车加 bi 单位汽油.假设卡车的燃料箱的容量是无限大的,无论加多少油都没有问题

数据结构--左式堆的思想和代码

左式堆也是实现优先列队的一种数据结构,和二叉堆一样,左式堆也具有堆序性和结构性. 堆序性: 一个节点的后裔都大于等于这个节点. 结构性:左式堆也是二叉树,和二叉堆的唯一区别在于左式堆不是理想平衡的,实际上是趋于非常不平衡,对于堆中每一个节点X,左儿子的零路径长至少与右儿子的零路径长一样大,零路径长Npl的定义为:节点到一个没有两个儿子的节点的最短路径长,因此具有0个或者1个儿子节点的Npl为0,Npl(NULL) = -1. 左式堆可以高效的支持合并操作,而插入和删除操作都可以通过合并操作来实现

数据结构_二叉树Ⅲ——堆与优先队列

堆(Heap) 堆是一种完全二叉树,只是是用数组的形式表示二叉树而已 它其实是利用完全二叉树的结构来维护一组数据 例如这样一棵完全二叉树: 它用堆的形式表现就是这样的: 当然,一般的堆每个元素都是数字呢(不然小根堆与大根堆就没办法实现了呢) 大根堆与小根堆 顾名思义,大根堆/小根堆就是保证根节点是所有数据中最大/小,并且尽力让小的节点在上方 例如下面这个二叉树就是一个小根堆呢 (借鉴某书图片) 那如何将任意一个堆调整至大根堆/小根堆呢? 从上向下调整 让当前结点与它的左右孩子进行比较,哪个比较小

最大堆/最小堆/优先队列 实现代码(c++)

自我感觉代码写的比较乱,这方面要好好注意一下. 总结: 1.在使用vector<int>::size_type 类似的类型时,千万要注意循环的条件判断,很容易发生溢出的危险!所以我最后很懒的选择使用int  - -. 2.下标表示和元素个数表示之间的细微差别.下标之间的变换关系: 父节点 parent(i)=(i-1)/2; 左孩子 left(i)=2*i+1;右孩子 right(i)=2*i+2 class Max_Heap{ typedef int index; public: Max_H