Priority Queue实现栈和队列

在排序算法中,堆排序利用了完全二叉树形式的堆结构,结合了插入排序与合并排序的优点,能够以 O ( n log ⁡ n ) O(n\log{n}) O(nlogn)的时间完成排序。优先级队列是可基于堆结构进行实现的一种数据结构,在计算机系统中可以用来记录不同作业的相对优先级关系,从而进行作业调度。本文将介绍什么是优先级队列,以及使用优先级队列实现栈和队列的C语言算法。

1. 什么是优先级队列

优先级队列(Priority Queue)是一个具有有限元素的线性结构,其中每个元素都有一个数值key标识其优先级。优先级队列又可分为最大优先级队列最小优先级队列

1.1 最大优先级队列

一个最大优先级队列支持以下操作:

  • INSERT(S, x):把元素x插入集合S中;
  • MAXIMUM(S):返回集合S中具有最大优先级的元素;
  • EXTRACT-MAX(S):去掉并返回S中具有最大优先级的元素;
  • INCREASE-KEY(S, x, k):将元素x的优先级增加到k,这里假设k值不能小于x的原始关键字的值。

1.2 最小优先级队列

一个最小优先级队列支持以下操作:

  • INSERT(S, x):把元素x插入集合S中;
  • MINIMUM(S):返回集合S中具有最小优先级的元素;
  • EXTRACT-MIN(S):去掉并返回S中具有最小优先级的元素;
  • DECREASE-KEY(S, x, k):将元素x的优先级减小到k,这里假设k值不能大于x的原始关键字的值。

可以发现最大优先级队列与最小优先级队列的区别仅在于后三个操作针对的元素优先级不同。

2. 设计思路

在具体底层实现上,最大优先级队列可用大顶堆实现,最小优先级队列可用小顶堆实现。以大顶堆为例,它支持以下操作:

  • MAX-HEAPIFY:运行时间为 O ( log ⁡ n ) O(\log{n}) O(logn),保持最大堆性质;
  • BUILD-MAX-HEAP:以线性时间运行,将无序的输入数组转换为最大堆;
  • MAX-HEAP-INSERT, HEAP-EXTRACT-MAX, HEAP-INCREASE-KEYHEAP-MAXIMUM过程的运算时间为 O ( log ⁡ n ) O(\log{n}) O(logn) , 可以让堆结构作为优先队列使用。

小顶堆支持操作类似。在使用最大优先级队列实现栈和队列过程中,我将元素入栈(或队)的序号作为元素的优先级。在使用最小优先级队列实现队列的过程中,我将元素入队的序号的相反数作为元素的优先级。具体代码可见第3节。

3. 程序代码

以下C语言程序代码分别实现了:

  • 最大优先队列实现后进先出栈(进栈元素优先级递增),见stack.cpp
  • 最小优先队列实现先进先出队列(进队元素优先级递增),见queue_min_priority.cpp
  • 最大优先队列实现先进先出队列(进队元素优先级递减),见queue_max_priority.cpp

3.1 最大优先队列实现栈

stack.cpp代码如下,在stack.cpp中首先构建最大堆,实现最大优先队列,然后利用最大优先队列实现栈。

#include <stdio.h>
#include <stdlib.h>#define MIN -1000000  //定义最小的优先级 //最大优先级队列实现后进先出栈:1.利用最大堆实现最大优先队列,2.利用最大优先队列实现栈,进栈的元素优先级递增 
typedef struct Node {int elem;    //储存栈中的元素值 int key;     //为每一个进栈的元素赋一个优先级值 
} Node;typedef struct Stack {int length;  //栈的长度 Node *data;  //栈中的元素 
} Stack;/*************************************Part1.利用最大堆实现最大优先队列*************************************/ 
void swap(Node *a, Node *b) { //交换元素a与元素b Node tmp;tmp.elem = (*a).elem;tmp.key = (*a).key;(*a).elem = (*b).elem;(*a).key = (*b).key;(*b).elem = tmp.elem;(*b).key = tmp.key;
}void max_heapify(Node *a, int size, int i) { //使元素的优先级满足最大堆的性质 int left = 2 * i;         //i的左孩子 int right = 2 * i + 1;    //i的右孩子 int largest;              //选出具有最大优先级的元素,下标存在largest中 if (left <= size && a[left].key > a[i].key) {largest = left;}else {largest = i;}    if (right <= size && a[right].key > a[largest].key) {largest = right;}if (largest != i) { //具有最大优先级的元素是i的某个孩子结点 swap(&a[i], &a[largest]);max_heapify(a, size, largest); //递归调用 }
}void build_max_heap(Node *a, int size) { //构建最大堆 int i;for(i = size / 2; i >= 1; i--) {max_heapify(a, size, i);}     
}Node heap_maximum(Node *a) { //返回最大优先级队列中优先级最大的元素,即最大堆的顶 return a[1];
}void heap_increase_key(Node *a, int i, int key) { //将元素a[i]的优先级增加到 key if (key < a[i].key) {printf("New key is smaller than current key!(Error from heap_increase_key)\n");exit(0);}a[i].key = key;while (i > 1 && a[i / 2].key < a[i].key) {swap(&a[i], &a[i / 2]);i = i / 2;}
}Node heap_extract_max(Node *a, int *size) { //去掉并返回最大优先队列中具有最大优先级的元素 if (*size < 1) {printf("Heap underflow!(Error from heap_extract_max)\n");exit(-1);}Node max = a[1];a[1] = a[*size];(*size)--;max_heapify(a, *size, 1);return max;
}void max_heap_insert(Node *a, int *size, int key, int elem) { //向最大优先队列中插入元素,即扩展最大堆 (*size)++;a[*size].key = MIN;a[*size].elem = elem;heap_increase_key(a, *size, key);
}
/************************************************Part1 ends************************************************//*************************************Part2.利用最大优先队列实现栈操作*************************************/
bool is_stack_empty(Stack *s) { //判断栈是否为空 if ((*s).length == 0) return true;return false;
}void stack_push(Stack *s, int elem) { //入栈 Node *old = (*s).data;(*s).data = (Node *)malloc(((*s).length + 2) * sizeof(Node)); //开创新的空间 int i;for (i = 1; i <= (*s).length; i++) {(*s).data[i] = old[i];}free(old); //释放旧的空间 max_heap_insert(s->data, &s->length, s->length + 1, elem);
}int stack_getTop(Stack *s) { //获取栈顶元素 return heap_maximum(s->data).elem;
}int stack_pop(Stack *s) { //出栈 return heap_extract_max(s->data, &s->length).elem;
}int main() {Stack s;printf("Input the length of the stack:\n");scanf("%d", &s.length);s.data = (Node *)malloc((s.length + 1) * sizeof(Node));printf("Input the element:\n");int i;for(i = 1; i <= s.length; i++){s.data[i].key = i;scanf("%d", &s.data[i].elem);}printf("Build the heap for the stack!\n");build_max_heap(s.data, s.length);printf("The result of the heap:\n");for(i = 1; i <= s.length; i++)printf("%d(Priority:%d) ", s.data[i].elem, s.data[i].key);printf("\n");int push_elem;printf("Input the element you want to push into the stack:\n");scanf("%d", &push_elem);stack_push(&s, push_elem);printf("Now the top of the stack is: %d\n", stack_getTop(&s));printf("Output the stack:\n");while (!is_stack_empty(&s)) {printf("pop: %d\n", stack_pop(&s));}return 0;
}

3.2 最小优先队列实现队列

queue_min_priority.cpp中首先构建最小堆,实现最小优先队列,然后利用最小优先队列实现队列,代码如下:

#include <stdio.h>
#include <stdlib.h>#define MAX 1000000  //定义最大的优先级 //最小优先级队列实现先进先出队列:1.利用最小堆实现最小优先队列,2.利用最小优先队列实现队列,进队的元素优先级递增 
typedef struct Node {int elem;    //储存队列中的元素值 int key;     //为每一个进队的元素赋一个优先级值 
} Node;typedef struct Queue {int length;  //队列的长度 Node *data;  //队列中的元素 
} Queue;/*************************************Part1.利用最小堆实现最小优先队列*************************************/ 
void swap(Node *a, Node *b) { //交换元素a与元素b Node tmp;tmp.elem = (*a).elem;tmp.key = (*a).key;(*a).elem = (*b).elem;(*a).key = (*b).key;(*b).elem = tmp.elem;(*b).key = tmp.key;
}void min_heapify(Node *a, int size, int i) { //使元素的优先级满足最小堆的性质 int left = 2 * i;         //i的左孩子 int right = 2 * i + 1;    //i的右孩子 int smallest;              //选出具有最小优先级的元素,下标存在smallest中 if (left <= size && a[left].key < a[i].key) {smallest = left;}else {smallest = i;}    if (right <= size && a[right].key < a[smallest].key) {smallest = right;}if (smallest != i) { //具有最小优先级的元素是i的某个孩子结点 swap(&a[i], &a[smallest]);min_heapify(a, size, smallest); //递归调用 }
}void build_min_heap(Node *a, int size) { //构建最小堆 int i;for(i = size / 2; i >= 1; i--) {min_heapify(a, size, i);}     
}Node heap_minimum(Node *a) { //返回最小优先级队列中优先级最小的元素,即最小堆的顶 return a[1];
}void heap_decrease_key(Node *a, int i, int key) { //将元素a[i]的优先级减少到 key if (key > a[i].key) {printf("New key is larger than current key!(Error from heap_decrease_key)\n");exit(0);}a[i].key = key;while (i > 1 && a[i / 2].key > a[i].key) {swap(&a[i], &a[i / 2]);i = i / 2;}
}Node heap_extract_min(Node *a, int *size) { //去掉并返回最小优先队列中具有最小优先级的元素 if (*size < 1) {printf("Heap underflow!(Error from heap_extract_min)\n");exit(-1);}Node min = a[1];a[1] = a[*size];(*size)--;min_heapify(a, *size, 1);return min;
}void min_heap_insert(Node *a, int *size, int key, int elem) { //向最小优先队列中插入元素,即扩展最小堆 (*size)++;a[*size].key = MAX;a[*size].elem = elem;heap_decrease_key(a, *size, key);
}
/************************************************Part1 ends************************************************//************************************Part2.利用最小优先队列实现队列操作************************************/
bool is_queue_empty(Queue *q) { //判断队列是否为空 if ((*q).length == 0) return true;return false;
}void queue_push(Queue *q, int elem) { //入队 Node *old = (*q).data;(*q).data = (Node *)malloc(((*q).length + 2) * sizeof(Node)); //开创新的空间 int i;for (i = 1; i <= (*q).length; i++) {(*q).data[i] = old[i];}free(old); //释放旧的空间 min_heap_insert(q->data, &q->length, q->length + 1, elem);
}int queue_getHead(Queue *q) { //获取队首元素 return heap_minimum(q->data).elem;
}int queue_pop(Queue *q) { //出队 return heap_extract_min(q->data, &q->length).elem;
}int main() {Queue q;printf("Input the length of the queue:\n");scanf("%d", &q.length);q.data = (Node *)malloc((q.length + 1) * sizeof(Node));printf("Input the element:\n");int i;for(i = 1; i <= q.length; i++){q.data[i].key = i;scanf("%d", &q.data[i].elem);}printf("Build the heap for the Queue!\n");build_min_heap(q.data, q.length);printf("The result of the heap:\n");for(i = 1; i <= q.length; i++)printf("%d(Priority:%d) ", q.data[i].elem, q.data[i].key);printf("\n");int push_elem;printf("Input the element you want to push into the queue:\n");scanf("%d", &push_elem);queue_push(&q, push_elem);printf("Now the head of the queue is: %d\n", queue_getHead(&q));printf("Output the queue:\n");while (!is_queue_empty(&q)) {printf("pop: %d\n", queue_pop(&q));}return 0;
}

3.3 最大优先队列实现队列

queue_max_priority.cpp实现过程同stack.cpp,只是优先级不同,代码如下:

#include <stdio.h>
#include <stdlib.h>#define MIN -1000000  //定义最小的优先级 //最大优先级队列实现先进先出队列:1.利用最大堆实现最大优先队列,2.利用最大优先队列实现队列,进队的元素优先级递减 
typedef struct Node {int elem;    //储存队列中的元素值 int key;     //为每一个进队的元素赋一个优先级值 
} Node;typedef struct Queue {int length;  //队列的长度 Node *data;  //队列中的元素 
} Queue;/*************************************Part1.利用最大堆实现最大优先队列*************************************/ 
void swap(Node *a, Node *b) { //交换元素a与元素b Node tmp;tmp.elem = (*a).elem;tmp.key = (*a).key;(*a).elem = (*b).elem;(*a).key = (*b).key;(*b).elem = tmp.elem;(*b).key = tmp.key;
}void max_heapify(Node *a, int size, int i) { //使元素的优先级满足最大堆的性质 int left = 2 * i;         //i的左孩子 int right = 2 * i + 1;    //i的右孩子 int largest;              //选出具有最大优先级的元素,下标存在largest中 if (left <= size && a[left].key > a[i].key) {largest = left;}else {largest = i;}    if (right <= size && a[right].key > a[largest].key) {largest = right;}if (largest != i) { //具有最大优先级的元素是i的某个孩子结点 swap(&a[i], &a[largest]);max_heapify(a, size, largest); //递归调用 }
}void build_max_heap(Node *a, int size) { //构建最大堆 int i;for(i = size / 2; i >= 1; i--) {max_heapify(a, size, i);}     
}Node heap_maximum(Node *a) { //返回最大优先级队列中优先级最大的元素,即最大堆的顶 return a[1];
}void heap_increase_key(Node *a, int i, int key) { //将元素a[i]的优先级增加到 key if (key < a[i].key) {printf("New key is smaller than current key!(Error from heap_increase_key)\n");exit(0);}a[i].key = key;while (i > 1 && a[i / 2].key < a[i].key) {swap(&a[i], &a[i / 2]);i = i / 2;}
}Node heap_extract_max(Node *a, int *size) { //去掉并返回最大优先队列中具有最大优先级的元素 if (*size < 1) {printf("Heap underflow!(Error from heap_extract_max)\n");exit(-1);}Node max = a[1];a[1] = a[*size];(*size)--;max_heapify(a, *size, 1);return max;
}void max_heap_insert(Node *a, int *size, int key, int elem) { //向最大优先队列中插入元素,即扩展最大堆 (*size)++;a[*size].key = MIN;a[*size].elem = elem;heap_increase_key(a, *size, key);
}
/************************************************Part1 ends************************************************//************************************Part2.利用最大优先队列实现队列操作************************************/
bool is_queue_empty(Queue *q) { //判断队列是否为空 if ((*q).length == 0) return true;return false;
}void queue_push(Queue *q, int elem) { //入队 Node *old = (*q).data;(*q).data = (Node *)malloc(((*q).length + 2) * sizeof(Node)); //开创新的空间 int i;for (i = 1; i <= (*q).length; i++) {(*q).data[i] = old[i];}free(old); //释放旧的空间 max_heap_insert(q->data, &q->length, -1 * (q->length + 1), elem);
}int queue_getHead(Queue *q) { //获取队首元素 return heap_maximum(q->data).elem;
}int queue_pop(Queue *q) { //出队 return heap_extract_max(q->data, &q->length).elem;
}int main() {Queue q;printf("Input the length of the queue:\n");scanf("%d", &q.length);q.data = (Node *)malloc((q.length + 1) * sizeof(Node));printf("Input the element:\n");int i;for(i = 1; i <= q.length; i++){q.data[i].key = (-1) * i;scanf("%d", &q.data[i].elem);}printf("Build the heap for the Queue!\n");build_max_heap(q.data, q.length);printf("The result of the heap:\n");for(i = 1; i <= q.length; i++)printf("%d(Priority:%d) ", q.data[i].elem, q.data[i].key);printf("\n");int push_elem;printf("Input the element you want to push into the queue:\n");scanf("%d", &push_elem);queue_push(&q, push_elem);printf("Now the top of the queue is: %d\n", queue_getHead(&q));printf("Output the queue:\n");while (!is_queue_empty(&q)) {printf("pop: %d\n", queue_pop(&q));}return 0;
}

4. 运行结果

4.1 stack.cpp

  1. 首先用户需要输入stack的长度,然后为其输入栈中的元素。程序会给出栈中元素按优先级构造的最大堆结果。
  2. 之后程序会提示用户再次输入一个想要入栈的元素,按下回车,程序输出现在的栈顶元素,并将栈中的所有元素弹出。
    在这里插入图片描述

4.2 queue_min_priority.cpp

  1. 首先用户需要输入队列的长度,然后为其输入队列中的元素。程序会给出队列中元素按优先级构造的最小堆结果。
  2. 之后程序会提示用户再次输入一个想要入队的元素,按下回车,程序输出现在的队首元素,并将队列中的所有元素弹出。
    在这里插入图片描述

4.3 queue_max_priority.cpp

  1. 首先用户需要输入队列的长度,然后为其输入队列中的元素。程序会给出队列中元素按优先级构造的最大堆结果。
  2. 之后程序会提示用户再次输入一个想要入队的元素,按下回车,程序输出现在的队首元素,并将队列中的所有元素弹出。
    在这里插入图片描述

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

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

相关文章

[AIGC] SQL中的数据添加和操作:数据类型介绍

SQL&#xff08;结构化查询语言&#xff09;作为一种强大的数据库查询和操作工具&#xff0c;它能够完成从简单查询到复杂数据操作的各种任务。在这篇文章中&#xff0c;我们主要讨论如何在SQL中添加&#xff08;插入&#xff09;数据&#xff0c;以及在数据操作过程中&#xf…

安装MQTTfx,并且模拟MQTT订阅发布

&#xff08;一&#xff09;软件安装 下面给出了mqttfx官网的链接&#xff0c;可以使用官网进行下载软件&#xff0c;不过因为一些可知的原因&#xff0c;可能无法打开&#xff0c;那么你可以使用我提供的百度网盘进行下载安装。 官网链接&#xff1a;Softblade GmbH - Home …

h5增强表单---数据列表和属性

h5增强表单---数据列表 下拉列表 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</ti…

Agent Workflows(智能体工作流)

1.目前使用LLM的方式 目前&#xff0c;我们主要在零样本模式下使用大型语言模型&#xff08;LLM&#xff09;&#xff0c;通过提供提示&#xff08;prompt&#xff09;&#xff0c;模型逐词&#xff08;token&#xff09;地构建最终的输出内容&#xff0c;其间并未实施任何操作…

【新手教程】mmselfsup训练教程及常见报错处理

mmselfsup教程 1.安装mmselfsup2.了解文件结构与配置3.训练常见报错1.报错&#xff1a;FileNotFoundError: [Errno 2] No such file or directory:data/imagenet/train/./train/n04311004/images/n04311004_194.JPEG2.报错&#xff1a;报错ImportError: /mmcv/_ext.cpython-38-…

IT运维服务规范标准与实施细则

一、 总则 本部分规定了 IT 运维服务支撑系统的应用需求&#xff0c;包括 IT 运维服务模型与模式、 IT 运维服务管理体系、以及 IT 运维服务和管理能力评估与提升途径。 二、 参考标准 下列文件中的条款通过本部分的引用而成为本部分的条款。凡是注日期的引用文件&#xff0c…

由浅到深认识Java语言(7):方法(函数)

该文章Github地址&#xff1a;https://github.com/AntonyCheng/java-notes 在此介绍一下作者开源的SpringBoot项目初始化模板&#xff08;Github仓库地址&#xff1a;https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址&#xff1a;https://blog.c…

C语言——sizeof与strlen的对比

一.sizeof 我们在学习操作符的时候&#xff0c;就了解到了sizeof操作符&#xff0c;它的作用是求参数所占内存空间的大小&#xff0c;单位是字节。如果参数是一个类型&#xff0c;那就返回参数所占的字节数。 #include <stdio.h>int main() {int a 10;size_t b sizeo…

GEE入门及进阶教程|在 Earth Engine 中过滤图像集合

Earth Engine API 为 ImageCollection 类型提供了一组过滤器&#xff0c;过滤器可以根据空间、时间或属性特征来限制 ImageCollection&#xff0c;即可将图像从 ImageCollection 中分离出来以进行检查或操作。 图1 1 Earth Engine 中应用于图像集合的过滤、映射…

AugmentedReality之路-创建工程及主界面(1)

本文从零创建1个工程&#xff0c;并添加1个BasicMap和1个主界面&#xff0c;主界面包含Start AR和Stop AR两个按钮 1、创建移动端工程并打包运行 创建1个空工程&#xff0c;选择C&#xff0c;Mobile&#xff0c;Scalable&#xff0c;勾选StarterContent 通过Edit->Proje…

云原生网络魔术师:Docker高级网络实战演练与深度解析

在Docker的世界中&#xff0c;网络无疑是一块充满魔力的土地。当我们超越了基础的网络配置&#xff0c;步入Docker高级网络领域时&#xff0c;你会发现一个全新的、强大而灵活的网络模型正在等待你的探索。本文将带你亲历Docker高级网络实战操作&#xff0c;揭开overlay网络、自…

【数据分享】2012-2023年中国范围的逐年NPP/VIIRS夜间灯光数据(免费获取)

在之前的文章中我们分享了2012-2023年全球范围逐年NPP/VIIRS夜间灯光数据&#xff08;可查看之前的文章获悉详情&#xff09;&#xff01;很多小伙伴在拿到数据后&#xff0c;反映数据太大了&#xff0c; 有450G&#xff0c;下载非常不方便&#xff01;这个数据的范围是全球的&…