优先级队列

优先级队列的实现


前言

优先级队列是一种重要的数据结构,对于存储其中的元素,总是选择优先级最高的先出队,在优先队列中,每个元素都有一个与之关联的优先级,高优先级元素会排在队首,低优先级元素排在队尾。
实现优先队列的常用方式是使用堆排序实现。堆可以分为大顶堆和小顶堆,大顶堆的根节点总是大于左右节点,小顶堆的根节点总是小于左右节点。根据这个规则,可以通过不断地插入和删除操作,保证堆的有序性。


一、通过c++中的STL库对优先级队列进行实现

在优先级队列中元素具有优先级,越高优先级的元素越先出队。C++ STL库中已经提供了优先队列的实现。
下面是代码实现,一个是按元素大的优先出队,一个是按照元素小的优先出队

#include <iostream>
#include <queue>
#include <functional>

using namespace std;

int main() {
    priority_queue<int, vector<int>, less<int>>pq;
    priority_queue<int, vector<int>, greater<int>>pq1;
    pq.push(3);
    pq.push(1);
    pq.push(4);
    pq.push(1);
    pq1.push(3);
    pq1.push(1);
    pq1.push(4);
    pq1.push(1);
    

    while (!pq.empty()) {
        int top = pq.top();
        cout << top <<" ";
        pq.pop();
    }
    cout << endl;
    while (!pq1.empty()) {
        int top1 = pq1.top();
        cout << top1 <<" ";
        pq1.pop();
    }

    return 0;
}

这里使用了C++ STL库中的priority_queue实现。在定义priority_queue时,需要指定元素类型、底层容器类型和比较函数类型。使用less比较函数,即最大值优先;如果指定为greater比较函数,则最小值优先。

二、通过堆排序实现优先级队列

优先级队列可以通过堆来实现,堆是一种完全二叉数,可以通过数组来实现堆排序这一过程。
堆有两种操作:

插入(Insert):将元素插入堆的最后一层末尾,然后不断向上调整,保证堆的性质。

取出(Extract):取出堆的根节点,然后将最后一层最右边的节点与根节点交换,再不断向下调整,保证堆的性质。
代码如下:

#include<iostream>
using namespace std;

// 堆结构体
typedef struct {
    int* data;  // 数据指针
    int size;   // 堆的大小
    int capacity;  // 堆的容量
} Heap;

// 初始化堆
void init(Heap* h, int capacity) {
    h->data = new int[capacity + 1];  // 堆从1开始存储
    h->size = 0;
    h->capacity = capacity;
}

// 插入元素
void push(Heap* h, int value) {
    if (h->size >= h->capacity) return;  // 堆已满,插入失败
    int i = ++h->size;  // 把新元素放到堆底
    while (i > 1 && h->data[i / 2] > value) {  // 不断向上调整
        h->data[i] = h->data[i / 2];
        i /= 2;  // i指向它的父节点
    }
    h->data[i] = value;  // 插入新元素
}

// 取出元素
int pop(Heap* h) {
    if (h->size == 0) return -1;  // 堆为空,取出失败
    int value = h->data[1];  // 取出堆顶元素
    int last = h->data[h->size--];  // 取出堆底元素,并把堆的大小减1
    int i = 1, j = 2;  // j指向i的左子节点
    while (j <= h->size) {
        if (j + 1 <= h->size && h->data[j + 1] < h->data[j]) j++;  // 如果右子节点比左子节点小,就选右子节点
        if (last > h->data[j]) {  // 如果最后一个节点比j节点大,就继续向下调整
            h->data[i] = h->data[j];
            i = j;
            j *= 2;
        }
        else {
            break;
        }
    }
    h->data[i] = last;  // 把最后一个节点插入到i节点的位置
    return value;
}

int main() {
    Heap h;
    int value;
    init(&h, 1000);
    int n;
    cin >> n;
    for (int i = 0; i <n; i++) {
        cin >> value;
        push(&h, value);
    }
    for (int i = 0; i < n; i++) {
        cout<< pop(&h)<<" ";
    }
    return 0;
}


首先通过定义一个堆(Heap)的结构体,其中data是一个指向元素数组的指针,size是堆的大小,capacity是堆的容量。init函数用来初始化堆。push用来插入元素,先判断堆是否已满,然后将新元素插入到堆底,不断向上调整堆,直到插入位置符合堆的性质为止。pop函数用来取出元素,先判断堆是否为空,然后将堆顶元素取出,将堆底元素取出,将堆底元素放到堆顶,不断向下调整堆,直到堆符合性质为止。
先将最小的元素与最后一个元素调整位置,然后出队最小的元素,然后调整堆,不断循环实现堆排序的最小元素优先出队。

时间复杂度和空间复杂度

由于是通过最小堆实现的优先级队列,
时间复杂度:
插入操作(push)的时间复杂度是O(log n),其中n是堆的大小。每次插入操作可能需要进行最多log n次的比较和交换,以维持堆的性质。
删除操作(pop)的时间复杂度也是O(log n),因为每次删除操作同样可能需要进行最多log n次的比较和交换。
总的时间复杂度为O(n*logn)
空间复杂度:
初始化堆的空间复杂度是O(n),因为需要分配一个大小为n+1的数组来存储堆数据。
插入和删除操作的空间复杂度是O(1),因为这些操作只涉及到常数个变量的修改,不需要额外的空间

总结

实现优先级队列可以直接使用c++中的STL库中的优先级队列实现,也可以通过堆排序,可以分成大顶堆和小顶堆,实现优先级高的先出队。

  • 21
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值