一、队列的逻辑行为和操作说明
1. 逻辑行为
插入和删除分别在队列两端进行,队尾进,队头出
插入元素: 从队尾插入 入队
删除元素: 从队头删除 出队
先入先出 例如排队 银行的叫号系统
场景 什么时候需要队列:
队列可以作为快速处理的设备(程序)和慢速设备(程序)之间的中转站
常用队列来缓存,例如银行处理客户的服务人员很少,这时候就需要队列来缓存,假如只有1个服务人员,在10分钟内有7个人到银行,1可以不用排队,队列 2 3 4 5 6 7需要排队,结束1的业务之后就轮到2了。
2. 顺序存储的问题和解决方案
int data[5]; //为保证数组先入先出,需要有队头和队尾的索引,数组索引可以用下标表示
int rear; // 队尾
int front; // 队头
队列顺序存储时, data[rear] = e; rear++;
*e = data[front]; front++;
开始时,队列为空
元素开始入队,如下图,a,b,c三个元素依次入队
然后a,b依次出队
这时队列中只剩下c元素,d,e入队。我们发现e入队时,发生了溢出,但队列中只有3个元素,我们本来应该能存5个元素的,这种现象称为假溢出。
假溢出怎么解决 :
如果rear能回到索引为0的位置就可以了,原来弹出来的空间也可以用了。
rear,front只要在+的过程中一直在[0,4]之间就可以了,我们可以进行求模
rear = (rear + 1) % 5
front = (front + 1) % 5
循环队列
队满 不能入队 front == rear
队空 不能出队 front == rear
两个条件一样,无法判断条件满足时是队满还是队空。
那么如何区分循环队列的满和空的条件:
我们有两种常用方法
方法a.空余一个空间不用
满:front == (rear + 1) % max
空:front == rear
开始时,队列为空,front == rear
由于第一个空间要空出来不用,故rear先+1,然后再放入元素a,a入队
同样的,b,c,d入队
这时,front == (rear+1)%5,队满。
入队操作:rear = (rear+1)%5
出队操作:front = (front+1)%5
方法b. 加一个标志位(rear+1标志位的值为0,front+1标志位的值为1)
3. 链式存储的设计
入队:
新节点
rear->next = n;
rear = n;
出队:(备份思想)
tmp = front;
front = tmp->next;
free(tmp);
二、代码
先写一个头文件common.h来存放都要用的部分
#ifndef COMMON_H
#define COMMON_H
#include <stdio.h>
#include <stdlib.h>
typedef int Element;
#endif //COMMON_H
顺序队列(循环队列)
arrayQueue.h
#ifndef ARRAYQUEUE_H
#define ARRAYQUEUE_H
#include "common.h"
#define MaxQueue 5 //定义数据域
// 定义顺序队列的结构
typedef struct {
Element data[MaxQueue];
int front;//队首
int rear;//队尾
}ArrayQueue;
//产生队列
ArrayQueue *createArrayQueue();
//释放队列
void releaseArrayQueue(ArrayQueue *queue);
//入队(元素e进哪个队)
int enArrayQueue(ArrayQueue *queue, Element e);
//出队
int deArrayQueue(ArrayQueue *queue, Element *e);
#endif //ARRAYQUEUE_H
arrayQueue.c
#include "arrayQueue.h"
ArrayQueue *createArrayQueue() {
ArrayQueue *queue = (ArrayQueue *)malloc(sizeof(ArrayQueue));//申请队列
if (queue == NULL) {
printf(".....!\n");
return NULL;
}
queue->front = queue->rear = 0;//初始化开始时队首队尾索引都为0
return queue;
}
void releaseArrayQueue(ArrayQueue *queue) {
if (queue) {
free(queue);
}
}
//入队
int enArrayQueue(ArrayQueue *queue, Element e) {
// 先判断队列满不满
if ((queue->rear + 1) % MaxQueue == queue->front) {
printf("Queue full!\n");
return -1;
}
queue->rear = (queue->rear + 1) % MaxQueue;
queue->data[queue->rear] = e;
return 0;
}
//出队
int deArrayQueue(ArrayQueue *queue, Element *e) {
// 先判断队列空不空
if (queue->rear == queue->front) {
printf("Queue empty!\n");
return -1;
}
queue->front = (queue->front + 1) % MaxQueue;
*e = queue->data[queue->front];
return 0;
}
链式队列
linkQueue.h
#ifndef LINKQUEUE_H
#define LINKQUEUE_H
#include "common.h"
// 链式节点类型
typedef struct queNode {
Element data;
struct queNode *next;
}QueNode;
// 队列结构
typedef struct {
QueNode *front;
QueNode *rear;
int cnt; // 队列的元素个数
}LinkQueue;
LinkQueue *createLinkQueue();
void releaseLinkQueue(LinkQueue *queue);
int enLinkQueue(LinkQueue *queue, Element e);
int deLinkQueue(LinkQueue *queue, Element *e);
#endif //LINKQUEUE_H
linkQueue.c
#include "linkQueue.h"
#include "linkQueue.h"
LinkQueue *createLinkQueue() {
LinkQueue *linkQueue = (LinkQueue *) malloc(sizeof(LinkQueue));
if (linkQueue == NULL) {
printf(".....!\n");
return NULL;
}
linkQueue->front = linkQueue->rear = NULL;
linkQueue->cnt = 0;
return linkQueue;
}
int enLinkQueue(LinkQueue *queue, Element e) {
// 先申请节点
QueNode *node = (QueNode *) malloc(sizeof(QueNode));
if (node == NULL) {
printf("........!\n");
return -1;
}
node->data = e;
node->next = NULL;
if (queue->rear) { // 队尾已经指向了有效数据
queue->rear->next = node;
queue->rear = node;
} else { // 队尾为空,说明队列里没有元素
queue->rear = queue->front = node;
}
queue->cnt++;
return 0;
}
int deLinkQueue(LinkQueue *queue, Element *e) {
// 出队要进行判断,有没有元素
if (queue->front == NULL) {
printf("queue empty!\n");
return -1;
}
*e = queue->front->data;
QueNode *tmp = queue->front;
queue->front = tmp->next;
free(tmp);
queue->cnt--;
if (queue->front == NULL) { // 队列已经没有元素了
queue->rear = NULL;
}
return 0;
}
void releaseLinkQueue(LinkQueue *queue) {
if (queue) {
QueNode *node;
// 从队头开始逐个释放元素
while (queue->front) {
node = queue->front;
queue->front = node->next;
free(node);
queue->cnt--;
}
printf("queue have %d node!\n", queue->cnt);
free(queue);
}
}
main.c结果来测试
#include "arrayQueue.h"
#include "linkQueue.h"
// 测试顺序存储的循环队列
int test01() {
ArrayQueue *queue = createArrayQueue();//先产生一个队列
Element e;
//MaxQueue为5,我们要空一个空间不用,故我们只能存四个值
for (int i = 0; i < 4; ++i) {
enArrayQueue(queue, i + 100);
}
printf("===========!\n");
enArrayQueue(queue, 500);
printf("Queue:");
for (int i = 0; i < 4; ++i) {
deArrayQueue(queue, &e);
printf("\t%d", e);
}
printf("\n");
deArrayQueue(queue, &e);//这块要写成e的地址&e才能更新e
releaseArrayQueue(queue);
return 0;
}
// 测试链式队列
int test02() {
LinkQueue *queue = createLinkQueue();
Element e;
for (int i = 0; i < 6; ++i) {
enLinkQueue(queue, i + 50);
}
printf("cnt: %d\n", queue->cnt);
printf("Que:");
for (int i = 0; i < 5; ++i) {
deLinkQueue(queue, &e);
printf("\t%d", e);
}
printf("\n");
releaseLinkQueue(queue);
return 0;
}
int main() {
test01();
test02();
return 0;
}
顺序队列测试结果:
链式队列测试结果: