【数据结构C/C++】优先(级)队列

文章目录

  • 什么是优先队列?
  • 堆排序
  • 代码实现
  • 408考研各数据结构C/C++代码(Continually updating)

什么是优先队列?

下面的内容来自于百度百科。

如果我们给每个元素都分配一个数字来标记其优先级,不妨设较小的数字具有较高的优先级,这样我们就可以在一个集合中访问优先级最高的元素并对其进行查找和删除操作了。这样,我们就引入了优先级队列这种数据结构。 优先级队列(priority queue)
是0个或多个元素的集合,每个元素都有一个优先权,对优先级队列执行的操作有(1)查找(2)插入一个新元素 (3)删除
一般情况下,查找操作用来搜索优先权最大的元素,删除操作用来删除该元素 。对于优先权相同的元素,可按先进先出次序处理或按任意优先权进行。

简而言之,我们定义了一种数据结构,这种数据结构在插入数据的时候会按照优先级进行排序,从而使得每次取出的元素都会保证一定的顺序。
也就是说,在我们插入数据之后,会对当前数据结构进行一次排序。
在优先队列中,每个元素都与一个优先级相关联,这个优先级可以是一个数字、权重、时间戳或其他可以用来衡量元素重要性的值。

优先队列的主要特点是能够按照元素的优先级来进行插入、访问和删除操作,确保高优先级的元素在处理时具有更高的优先级。这使得优先队列在以下情况下非常有用:

任务调度:在任务管理中,不同的任务可能具有不同的紧急性或优先级。优先队列可用于选择下一个要执行的任务,确保高优先级任务首先执行。
图算法:在图算法中,如Dijkstra算法和Prim算法,需要选择具有最小权重的边或顶点。优先队列可用于高效地选择最小权重的元素。
事件模拟:在事件驱动系统中,事件具有不同的时间戳,应按照时间戳的顺序来处理。优先队列可用于管理事件并确保按时间戳的顺序执行。
数据压缩:在Huffman编码等数据压缩算法中,优先队列可用于构建最优编码树,以最小化压缩文件的大小。
资源分配:在资源管理中,资源可以按照优先级分配给不同的任务或请求,以确保最重要的任务获得优先访问资源。
网络路由:在网络路由中,优先队列可用于选择最佳路径,以最小化延迟或最大化带宽利用率。

在我开发代码的过程中,优先队列最常用最常用的场景就是做一个任务调度系统,来保证高优先级的任务都会较早被执行。

堆排序

如果了解堆排序的,就会明白,优先队列的实现原理和堆排序其实差不多。
堆排序在不断遍历堆的过程中会不断的将堆变成大顶堆或者小顶堆,这很明显就符合我们对优先队列的要求。也就是每次堆顶都是高优先级的数据。
堆排序

代码实现

基于上面的特性,优先队列可以用多种不同的数据结构来实现,包括二叉堆(Binary Heap)、斐波那契堆(Fibonacci Heap)、二项堆(Binomial Heap)、左偏树(Leftist Tree)等。每种实现方式都有其优点和缺点,适用于不同类型的问题。
对于优先队列,我们可以选择支持动态扩展容量,也可以选择固定容量,在容量过大后不允许插入新元素。具体选择那种方式看你的业务需求。
这里我们就掌握常用的基于堆的方式实现的优先队列。代码如下:

#include <stdio.h>
#include <stdlib.h>// 结构体表示小顶堆
typedef struct PriorityQueue {int* heap;int capacity;int size;
} PriorityQueue;// 创建小顶堆,初始化容量
PriorityQueue* createPriorityQueue(int capacity) {PriorityQueue* pq = (PriorityQueue*)malloc(sizeof(PriorityQueue));pq->capacity = capacity;pq->size = 0;pq->heap = (int*)malloc(capacity * sizeof(int));return pq;
}// 交换两个整数的值
void swap(int* a, int* b) {int temp = *a;*a = *b;*b = temp;
}// 向小顶堆中插入元素
void offer(PriorityQueue* pq, int element) {if (pq->size == pq->capacity) {// 队列已满,需要扩展pq->capacity *= 2;pq->heap = (int*)realloc(pq->heap, pq->capacity * sizeof(int));}int currentIndex = pq->size;pq->heap[currentIndex] = element;while (currentIndex > 0) {int parentIndex = (currentIndex - 1) / 2;if (pq->heap[currentIndex] >= pq->heap[parentIndex]) {break;}swap(&pq->heap[currentIndex], &pq->heap[parentIndex]);currentIndex = parentIndex;}pq->size++;
}// 从小顶堆中移除并返回最小值
int poll(PriorityQueue* pq) {if (pq->size == 0) {// 队列为空exit(1); // 或者返回一个错误值,具体情况而定}int min = pq->heap[0];int last = pq->heap[pq->size - 1];pq->size--;if (pq->size > 0) {pq->heap[0] = last;int currentIndex = 0;while (1) {int leftChildIndex = 2 * currentIndex + 1;int rightChildIndex = 2 * currentIndex + 2;int smallest = currentIndex;if (leftChildIndex < pq->size && pq->heap[leftChildIndex] < pq->heap[smallest]) {smallest = leftChildIndex;}if (rightChildIndex < pq->size && pq->heap[rightChildIndex] < pq->heap[smallest]) {smallest = rightChildIndex;}if (smallest == currentIndex) {break;}swap(&pq->heap[currentIndex], &pq->heap[smallest]);currentIndex = smallest;}}return min;
}// 返回小顶堆中的最小值,不移除
int peek(PriorityQueue* pq) {if (pq->size == 0) {// 队列为空exit(1); // 或者返回一个错误值,具体情况而定}return pq->heap[0];
}// 检查小顶堆是否为空
int isEmpty(PriorityQueue* pq) {return pq->size == 0;
}// 返回小顶堆的大小
int size(PriorityQueue* pq) {return pq->size;
}// 销毁小顶堆并释放内存
void destroyPriorityQueue(PriorityQueue* pq) {free(pq->heap);free(pq);
}int main() {int capacity = 10;PriorityQueue* minHeap = createPriorityQueue(capacity);int userInput;printf("输入元素(输入-1结束):\n");while (1) {scanf("%d", &userInput);if (userInput == -1) {break;}offer(minHeap, userInput);}printf("大小: %d\n", size(minHeap));printf("堆顶元素: %d\n", peek(minHeap));printf("出堆并打印元素:\n");while (!isEmpty(minHeap)) {printf("%d ", poll(minHeap));}printf("\n");destroyPriorityQueue(minHeap);return 0;
}

408考研各数据结构C/C++代码(Continually updating)

408考研各数据结构C/C++代码(Continually updating)
这个模块是我应一些朋友的需求,希望我能开一个专栏,专门提供考研408中各种常用的数据结构的代码,并且希望我附上比较完整的注释以及提供用户输入功能,ok,fine,这个专栏会一直更新,直到我认为没有新的数据结构可以讲解了。
目前我比较熟悉的数据结构如下:
数组、链表、队列、栈、树、B/B+树、红黑树、Hash、图。
所以我会先有空更新出如下几个数据结构的代码,欢迎关注。 当然,在我前两年的博客中,对于链表、哈夫曼树等常用数据结构,我都提供了比较完整的详细的实现以及思路讲解,有兴趣可以去考古。

#include <stdio.h>
#include <stdlib.h>// 结构体表示小顶堆
typedef struct PriorityQueue {int* heap;int capacity;int size;
} PriorityQueue;// 创建小顶堆,初始化容量
PriorityQueue* createPriorityQueue(int capacity) {PriorityQueue* pq = (PriorityQueue*)malloc(sizeof(PriorityQueue));pq->capacity = capacity;pq->size = 0;pq->heap = (int*)malloc(capacity * sizeof(int));return pq;
}// 交换两个整数的值
void swap(int* a, int* b) {int temp = *a;*a = *b;*b = temp;
}// 向小顶堆中插入元素
void offer(PriorityQueue* pq, int element) {if (pq->size == pq->capacity) {// 队列已满,需要扩展pq->capacity *= 2;pq->heap = (int*)realloc(pq->heap, pq->capacity * sizeof(int));}int currentIndex = pq->size;pq->heap[currentIndex] = element;while (currentIndex > 0) {int parentIndex = (currentIndex - 1) / 2;if (pq->heap[currentIndex] >= pq->heap[parentIndex]) {break;}swap(&pq->heap[currentIndex], &pq->heap[parentIndex]);currentIndex = parentIndex;}pq->size++;
}// 从小顶堆中移除并返回最小值
int poll(PriorityQueue* pq) {if (pq->size == 0) {// 队列为空exit(1); // 或者返回一个错误值,具体情况而定}int min = pq->heap[0];int last = pq->heap[pq->size - 1];pq->size--;if (pq->size > 0) {pq->heap[0] = last;int currentIndex = 0;while (1) {int leftChildIndex = 2 * currentIndex + 1;int rightChildIndex = 2 * currentIndex + 2;int smallest = currentIndex;if (leftChildIndex < pq->size && pq->heap[leftChildIndex] < pq->heap[smallest]) {smallest = leftChildIndex;}if (rightChildIndex < pq->size && pq->heap[rightChildIndex] < pq->heap[smallest]) {smallest = rightChildIndex;}if (smallest == currentIndex) {break;}swap(&pq->heap[currentIndex], &pq->heap[smallest]);currentIndex = smallest;}}return min;
}// 返回小顶堆中的最小值,不移除
int peek(PriorityQueue* pq) {if (pq->size == 0) {// 队列为空exit(1); // 或者返回一个错误值,具体情况而定}return pq->heap[0];
}// 检查小顶堆是否为空
int isEmpty(PriorityQueue* pq) {return pq->size == 0;
}// 返回小顶堆的大小
int size(PriorityQueue* pq) {return pq->size;
}// 销毁小顶堆并释放内存
void destroyPriorityQueue(PriorityQueue* pq) {free(pq->heap);free(pq);
}int main() {int capacity = 10;PriorityQueue* minHeap = createPriorityQueue(capacity);int userInput;printf("输入元素(输入-1结束):\n");while (1) {scanf("%d", &userInput);if (userInput == -1) {break;}offer(minHeap, userInput);}printf("大小: %d\n", size(minHeap));printf("堆顶元素: %d\n", peek(minHeap));printf("出堆并打印元素:\n");while (!isEmpty(minHeap)) {printf("%d ", poll(minHeap));}printf("\n");destroyPriorityQueue(minHeap);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/107904.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JAVAEE初阶相关内容第十四弹--网络初识

写在前&#xff1a; 这一部分开启网络部分的相关知识&#xff0c;这一弹内容初始网络将主要进行网络相关知识的简单介绍&#xff0c;以及着重介绍协议、协议分层、OSI七层模型、TCP/IP五层模型、封装和分用。 需要认识协议&#xff0c;并知道协议的效果是什么&#xff1b;知道…

不写注释就是耍流氓?

不写注释就是耍流氓&#xff1f; 关于写代码不写注释这么说“我”不想写注释的原因如何才能写出漂亮的注释 关于写代码不写注释这么说 关于代码注释的争论一直存在&#xff0c;程序员社区中有不同的观点和实践。写代码时是否应该写注释是一个有深度的话题&#xff0c;我认为需…

word如何设置页码?教你快速提升文档颜值!

在创建文档时&#xff0c;为了更好地组织内容&#xff0c;页码是一个必不可少的元素。但是很多人不知道word如何设置页码&#xff0c;其实word提供了多种设置页码的方法&#xff0c;以满足不同文档的需求。本文将详细介绍3种设置页码的方法&#xff0c;无论您是初学者还是有经验…

LMI FocalSpec 3D线共焦传感器 使用笔记1

一.硬件介绍 以上特别注意: 屏蔽线必须接地,因为在现场实际调试中,使用软件调试发现经常 弹窗 传感器丢失警告!! 以上 Position LED 的灯被钣金挡住,无法查看异常现象,能否将指示灯设置在软件界面上? 需要确认是软触发还是硬触发,理论上 硬触发比软触发速度要快.(我们目前使用…

LinkedList集合

LinkedList集合 底层数据结构是双链表,查询慢,增删快,但如果操做的是首元素,速度也是极快的 本身多了很多直接操做首尾元素的特有API 这些特有方法不常用,了解即可 LinkedList源码分析 迭代器的源码分析 iterator():生成一个迭代器对象,默认指向集合的0索引处hasNext():判…

javascript利用xhr对象实现http流的comet轮循,主要是利用readyState等于3的特点

//此文件 为前端获取http流 <!DOCTYPE html> <html xmlns"http://www.w3.org/1999/xhtml" lang"UTF-8"></html> <html><head><meta http-equiv"Content-Type" content"text/html; charsetUTF-8"/&g…

sqlserver系统存储过程添加用户学习

sqlserver有一个系统存储过程sp_adduser&#xff1b;从名字看是添加用户的&#xff1b;操作一下&#xff0c; 从错误提示看还需要先添加一个登录名&#xff0c;再执行一个系统过程sp_addlogin看一下&#xff0c; 执行完之后看一下&#xff0c;安全性-登录名下面有了rabbit&…

【Linux】屏蔽项目服务非正常日志输出到message文件中

屏蔽项目服务非正常日志输出到message文件中 # vi /etc/rsyslog.conf ### ....省略n行 :programname, isequal, "进程名" stop *.info;mail.none;authpriv.none;cron.none /var/log/messages### 或者 if $programname 进程名 then stop *.info;mail…

表结构的增删改(约束)、表数据的增删改、truncate总结归纳 | sql笔记自查用

和表的定义相关的语言 DDL&#xff1a;create、drop、alter 建表&#xff1a; create table tbl_student(stu_id int,stu_name varchar(32) );-- 查询结果放入新表 create table tbl_student_backup as select * from tbl_student;删表&#xff1a; drop table tbl_student;…

【JavaEE】初识网络

网络初识 文章目录 网络初识网络发展史独立模式网络互连局域网LAN广域网 网络通信基础IP地址端口号格式 协议五元组协议分层OSI七层模型TCP/IP五&#xff08;四&#xff09;层协议1.物理层2.数据链路层3.网络层4.传输层5.应用程序 网络设备所在的分层封装和分用例子发送方接收方…

ERP系统供应商协同:优化企业供应链管理

一、ERP系统供应商协同的概念和功能 供应商协同是指在供应链中&#xff0c;企业与供应商之间通过ERP系统进行紧密合作和信息共享&#xff0c;实现供应链各个环节的协调和优化。ERP系统供应商协同功能涉及以下方面&#xff1a; 1. 供应商管理&#xff1a;ERP系统提供完善的供应…

el-table添加fixed属性后底部滚动条添加小手

0 效果 1 样式 /deep/ .el-table--scrollable-x {cursor: pointer; } /deep/ .el-table__empty-block {cursor: auto; } /deep/ .el-table__row {cursor: auto; }

Docker 安装Redis

一、下载redis 镜像 docker pull redis 二、创建数据卷映射路径、配置redis.conf mkdir -p /usr/local/myredis/confvim redis.conf # redis.conf appendonly yes 配置内容可以参考 https://github.com/redis/redis/blob/unstable/redis.conf 启用内存过渡分配 #修改配置 vim…

深入剖析 深度学习中 __init()__函数和forward()函数

目录 前言1. __init()__函数2. forward()函数3. 两者关系 前言 再看代码时&#xff0c;发现init函数和forward函数都有参数&#xff0c;具体是怎么传参的呢&#xff1f; 为了更方便的讲解&#xff0c;会举简单的代码例子结合讲解。 forward() 和 __init__() 是神经网络模型类…

开源/免费的scrum工具:敏捷项目管理的选择

有许多开源和免费的敏捷管理工具可供敏捷团队使用&#xff0c;以支持他们的敏捷项目管理和开发需求。以下是一些常见的开源/免费敏捷管理工具&#xff1a; 免费敏捷工具 以下是一些免费的敏捷工具&#xff0c;这些工具提供了一定的功能&#xff0c;可用于支持敏捷项目管理和开…

13-k8s-ingress网络

文章目录 一、ingress介绍二、创建nginx和tomcat供测试三、创建ingress-http四、yaml方式安装ingress五、helm方式安装ingress&#xff08;推荐&#xff09;六、Ingress的HTTPS代理 一、ingress介绍 Service对集群之外暴露服务的主要方式有两种&#xff1a;NotePort和LoadBalan…

VulnHub Alice

一、信息收集 发现开发了22、80 2.访问ip&#xff0c;右击查看源代码 发现需要利用X-Forwarded-For 火狐插件&#xff1a;X-Forwarded-For Header 挂上代理后&#xff1a; 出现以下页面&#xff1a; 先注册一个账户&#xff0c;然后再登录 发现有参数进行传参 发现传参&a…

从Flink的Kafka消费者看算子联合列表状态的使用

背景 算子的联合列表状态是平时使用的比较少的一种状态&#xff0c;本文通过kafka的消费者实现来看一下怎么使用算子列表联合状态 算子联合列表状态 首先我们看一下算子联合列表状态的在进行故障恢复或者从某个保存点进行扩缩容启动应用时状态的恢复情况 算子联合列表状态主…

用建筑中智能消防应急照明系统的应用

【摘要】&#xff1a;火灾应急照明是火灾安全疏散、保障消防人员生命安全的关键。对电气设计人员来说&#xff0c;火灾紧急照明系统的设计非常必要&#xff0c;消防紧急照明系统启动与其正常工作状态有直接的关系&#xff0c;但由于其存在的问题通常不能被及时发现&#xff0c;…

ubuntu 22.04版本修改服务器名、ip,dns信息的操作方法

总结 1、ubuntu修改服务器名重启后生效的方法是直接修改/etc/hostname文件 2、ubuntu 22.04操作系统配置ip和dns信息&#xff0c;一般只需要使用netplan命令行工具来配置就行&#xff0c;在/etc/netplan/在目录下创建一个yaml文件就可以实现ip和dns的配置&#xff0c;当然如果…