本文介绍了循环优先级队列的使用方法,代码由c语言实现,但了解相关思想后,使用c++、python等语言也可通过数组来快速实现循环优先级队列
前言
之前写了一篇使用c语言实现循环队列的,后来由于需要,个人又基于它实现了循环优先级队列。
一、循环优先级队列是什么?
之前所介绍的循环队列是先入先出的,很容易用平常的排队来理解。但如果这个队列要支持有紧急情况的人先出队呢?原先那种队列就不再适用了,我们就需要使用本文所提到的特殊队列–优先队列。
优先队列也是一种抽象数据类型。优先队列中的每个元素都有优先级,而优先级高(或者低)的将会先出队,而优先级相同的则按照其在优先队列中的顺序依次出队。
这样采用数组实现时,可以有两种方式,一种是以O(1)复杂度插入,每次在队尾入队,而以O(N)复杂度弹出最小元素;或者以O(N)复杂度插入,保持数组有序,而以O(1)复杂度删除。另一种则是使用堆来实现,堆可以认为是用数组实现的二叉树,可以在O(log N)的复杂度内实现元素的插入和删除。
在本文中采用的是第一种方式,即可在O(n)的时间复杂度内插入,O(1)的复杂度内弹出。
二、c语言实现
1.整体结构
代码如下(示例):
#define QUEUE_SIZE (1024)
struct queue {
int data[QUEUE_SIZE];
int priority[QUEUE_SIZE];
int front;
int tail;
int empty;
};
void init(struct queue *);
void enqueue(struct queue *, int, int);
int dequeue(struct queue *);
同前述,data数组用于保存队列中数据,priority用于保存队列中各数据权重,priority值越小,越容先出队,front是队首元素索引,tail是队尾元素索引+1,empty表示队列是否为空。各函数的具体实现如下:
2.函数实现
代码如下(示例):
#include "queue.h"
#include <stdio.h>
void init(struct queue *q)
{
q->front = q->tail = 0;
q->empty = 1;
}
// value表示要插入队列的元素的值,prio为其权重
void enqueue(struct queue *q, int value, int prio)
{
if (!q->empty && q->front == q->tail) {
printf("queue shouldn't be overflow\n");
exit(-1);
}
q->empty = 0;
int i = (q->tail - 1 + QUEUE_SIZE) % QUEUE_SIZE, j = q->tail,
head = (q->front - 1 + QUEUE_SIZE ) % QUEUE_SIZE;
// head为队首索引-1,当i==head,意味着队列中所有的元素都比较完毕
// i表示当前需要与value进行比较的元素的索引,j则为(i+1) % QUEUE_SIZE
while( i != head) {
if( q->priority[i] <= prio)
break;
q->data[j] = q->data[i];
q->priority[j] = q->priority[i];
j = i;
i = (i - 1 + QUEUE_SIZE) % QUEUE_SIZE;
}
q->data[j] = value;
q->priority[j] = prio;
q->tail = (q->tail + 1) % QUEUE_SIZE;
}
int dequeue(struct queue *q)
{
if (q->empty)
return -1;
int value = q->data[q->front];
q->front = (q->front + 1) % QUEUE_SIZE;
if (q->front == q->tail)
q->empty = 1;
return value;
}
与循环队列改动较大的主要是enqueue函数,为实现插入后队列中的元素仍按权重保持有序,显然需要将入队元素插入在合适的位置中;函数中即按照这一思想,从队列尾开始,采用冒泡的方式,将priority值大的元素都向后挪一个单位
总结
以上就是循环队列c语言的简单实现,上述思想也可适用于像c++、java等,都可通过数组来快速实现简单的循环优先级队列