算法竞赛里面的STL——堆和priority_queue

目录

1.堆

2.优先级队列 (priority_queue的中文翻译)

3.创建priority_queue-初阶

4.priority_queue常用的接口函数

5.priority_queue里面存的是结构体的情况

题目一——第 k 小 

题目二——除2!

题目三——1046. 最后一块石头的重量 - 力扣(LeetCode) 

题目四——703. 数据流中的第 K 大元素 - 力扣(LeetCode) 

题目五——P2085 最小函数值 - 洛谷 | 计算机科学教育新生态

题目六——P1631 序列合并 - 洛谷 | 计算机科学教育新生态 

题目七——P1878 舞蹈课 - 洛谷 | 计算机科学教育新生态 

题目八——692. 前K个高频单词 - 力扣(LeetCode) 

题目九——295. 数据流的中位数 - 力扣(LeetCode) 


1.堆

首先我们得知道堆是啥? 

如果想要详细了解这个堆的话可以去下面这4篇文章看看

  1. 堆的介绍,堆的向下调整算法,堆的向上调整算法_堆调整-CSDN博客
  2. 堆的基本操作(c语言实现)_c语言堆的基本操作-CSDN博客
  3. 堆的应用1——堆排序-CSDN博客
  4. 堆的应用2——TOPK问题-CSDN博客

但是我还是要简单的介绍一下,什么是堆?

        堆在计算机科学中有广泛的应用,尤其是在实现优先队列和堆排序算法中。优先队列是一种数据结构,其中元素的优先级决定了它们的出队顺序。堆可以作为一种高效的优先队列实现方式,因为堆顶元素总是优先级最高(最大或最小)的元素。堆排序算法则利用堆的性质,通过构建最大堆或最小堆,并反复取出堆顶元素来实现排序。

将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

堆的性质:

  1. 堆中某个节点的值总是不大于或不小于其父节点的值;
  2. 堆总是一棵完全二叉树。

堆的分类 

堆主要分为两种类型:最大堆(Max Heap)和最小堆(Min Heap)。

  1. 在最大堆中,父节点的值总是大于或等于其子节点的值,因此堆顶元素是整个堆中的最大值。
  2. 相反,在最小堆中,父节点的值总是小于或等于其子节点的值,堆顶元素是整个堆中的最小值。 

我们先练习一下什么是大根堆?什么是小根堆?

2.优先级队列 (priority_queue的中文翻译)

普通的队列是⼀种先进先出的数据结构,即元素插⼊在队尾,⽽元素删除在队头。

⽽在优先级队列中,元素被赋予优先级,当插⼊元素时,同样是在队尾,但是会根据优先级进⾏位置调整,优先级越⾼,调整后的位置越靠近队头;

同样的,删除元素也是根据优先级进⾏,优先级最⾼ 的元素(队头)最先被删除。

其实可以认为,优先级队列就是堆实现的⼀个数据结构。 priority_queue 就是C++提供的,已经实现好的优先级队列,底层实现就是⼀个堆结构。

在算法竞赛 中,如果是需要使⽤堆的题⽬,⼀般就直接⽤现成的priority_queue,很少⼿写⼀个堆,因为省事~

3.创建priority_queue-初阶

优先级队列的创建结果有很多种,因为需要根据实际需求,可能会创建出各种各样的堆。这些堆可能包括:

  1. 简单内置类型的大根堆或小根堆:比如存储int类型的大根堆或小根堆。
  2. 存储字符串的大根堆或小根堆。
  3. 存储自定义类型的大根堆或小根堆:比如堆里面的数据是一个结构体。

关于每一种创建结果,都需要有与之对应的写法。在初阶阶段,先用简单的int类型建堆,重点学习priority_queue的用法。

注意:priority_queue包含在<queue>这个头文件中。

看看最简单的int类型的大根堆

#include <queue>
#include <vector>
#include <iostream>

using namespace std;
int main() {
    // 创建一个空的priority_queue,默认是大根堆,基础容器类型是vector
    priority_queue<int> pq;

    // 插入元素
    pq.push(1);
    pq.push(4);
    pq.push(2);
    pq.push(8);

    // 输出并移除顶部元素(优先级最高的元素)
    while (!pq.empty()) {
        cout << pq.top() << " "; // 输出8 4 2 1
        pq.pop();
    }

    return 0;
}

 看看另外两种初始化类型

 在C++中,priority_queue是一个模板类,它通常用于实现堆数据结构。堆是一种特殊的完全二叉树,它满足堆性质:对于大根堆(max-heap),每个节点的值都大于或等于其子节点的值;对于小根堆(min-heap),每个节点的值都小于或等于其子节点的值。

priority_queue的模板参数有三个:

  1. 数据类型:这是堆中存储的元素类型。
  2. 存数据的结构:这是底层容器类型,用于实际存储堆中的元素。priority_queue默认使用std::vector作为底层容器,但你也可以指定其他容器类型(只要它支持随机访问迭代器)。
  3. 数据之间的比较方式:这是一个函数对象(通常是一个仿函数或函数指针),用于比较堆中的元素,以确定它们的优先级。默认情况下,priority_queue使用std::less作为比较方式,这创建了一个大根堆。如果你想要一个小根堆,可以使用std::greater

现在,让我们具体讲解你给出的代码:

创建大根堆

priority_queue<int, vector<int>, less<int>> heap2; // 也是大根堆

  • 数据类型int。这意味着堆中存储的元素是整数。
  • 存数据的结构vector<int>。这指定了底层容器是一个整数向量。这是可选的,因为priority_queue默认使用std::vector
  • 数据之间的比较方式less<int>。这是一个函数对象,它比较两个整数并返回true如果第一个整数小于第二个整数(在实际上,less<int>的实现会返回false,因为我们是用它来构建大根堆的,但这里的逻辑是反向的——即,如果a < b则返回false意味着a的优先级不低于b,因此a应该留在堆顶或更高的位置)。然而,在这个特定的例子中,使用less<int>实际上是多余的,因为priority_queue默认就使用std::less来创建大根堆。

因此,heap2是一个大根堆,它存储整数,使用向量作为底层容器,并使用默认的(或显式指定的)std::less<int>比较函数来确定元素的优先级。在这个堆中,优先级最高的元素(即值最大的元素)总是在堆顶。


创建小根堆 

 如果你想要创建一个小根堆,你可以这样做:

priority_queue<int, vector<int>, greater<int>> heap3; // 小根堆

在这个例子中,greater<int>是一个函数对象,它比较两个整数并返回true如果第一个整数大于第二个整数(实际上,对于小根堆来说,如果a > b则返回false意味着a的优先级不高于b,因此b应该留在堆顶或更高的位置)。这样,heap3就是一个小根堆,其中值最小的元素总是在堆顶。

4.priority_queue常用的接口函数

size 和 empty函数

  1. size:返回优先级队列中元素的个数。

  2. empty:检查优先级队列是否为空。

O(1)时间复杂度:sizeempty操作都可以在常数时间内完成。 


push函数

  • 往优先级队列里面添加一个元素。

时间复杂度:由于底层是一个堆结构,所以添加元素的时间复杂度为O(log n),其中n是优先级队列中的元素数量。


pop函数

  • 删除优先级最高的元素。

时间复杂度:由于底层是一个堆结构,所以删除优先级最高的元素的时间复杂度为O(log n),其中n是优先级队列中的元素数量。


top函数

  • 获取优先级最高的元素,但不删除它。

时间复杂度:O(1)。获取优先级最高的元素可以在常数时间内完成,因为这个元素总是位于堆的顶端(对于大根堆)或底端(对于小根堆,取决于具体实现)。


接下来我们好好举一个例子来说明 

#include <iostream>
#include <queue>
#include <vector>

int main() {
    // 创建一个空的优先级队列(大根堆)
    std::priority_queue<int> pq;

    // 检查队列是否为空
    if (pq.empty()) {
        std::cout << "Priority queue is initially empty." << std::endl;
    }

    // 向队列中添加元素
    pq.push(10);
    pq.push(20);
    pq.push(15);

    // 获取队列的大小
    std::cout << "Size of priority queue after pushes: " << pq.size() << std::endl;

    // 获取并输出优先级最高的元素(但不删除)
    int topElement = pq.top();
    std::cout << "Top element (highest priority): " << topElement << std::endl; // 输出20

    // 删除优先级最高的元素
    pq.pop();

    // 再次获取队列的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值