一、顺序存储队列
队列(Queue):是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
队列是一种先进先出(FIFO) 的线性表。允许插入的一端称为队尾,允许删除的一端称为队头。
1.顺序存储队列假溢出

为了解决“假溢出”的问题,我们引入循环队列。
2.循环队列
就是队后面满了,再从头开始,也就是头尾相接的循环。我们把队列的这种头尾相接的顺序存储结构称为循环队列。

此时问题又来了,如上图第4个,队满时发现rear指针与front重合了,刚才说了,当rear=front时,表示是空队列,现在当队列满时,rear也等于front。那么如何判断队列到底是空的还是满的了?
解决办法为:当队列空时,判断条件就是rear=front, 当队列满时,我们修改其判断条件,保留一个元素空闲。也就是说,队列满时,数组中还有一个空闲单元。
由于rear可能比front大,也可能比front小,所以假设队列的最大尺寸为MaxSize, 队列满的判断条件改为(rear + 1)% MaxSize = front. 队列的长度为(rear - front + MaxSize)% MaxSize.
3.结构
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include "time.h"
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20 /* 存储空间初始分配量 */
typedef int Status;
typedef int QElemType; /* QElemType类型根据实际情况而定,这里假设为int */
循环队列的顺序存储结构
typedef struct {
QElemType data[MAXSIZE];
int front; /* 头指针 */
int rear; /* 尾指针,若队列不空,指向队列尾元素的下一个位置 */
}SqQueue;
4.初始化一个空队列Q
Status InitQueue(SqQueue *Q){
Q->front = 0;
Q->rear = 0;
return OK;
}
5.清空队列
Status ClearQueue(SqQueue *Q){
Q->front = Q->rear = 0;
return OK;
}
6.判断是否为空
Status QueueEmpty(SqQueue Q){
//队空标记
if (Q.front == Q.rear)
return TRUE;
else
return FALSE;
}
7.长度
int QueueLength(SqQueue Q){
return (Q.rear - Q.front + MAXSIZE)%MAXSIZE;
}
8.获取队头元素
Status GetHead(SqQueue Q,QElemType *e){
//队列已空
if (Q.front == Q.rear)
return ERROR;
*e = Q.data[Q.front];
return OK;
}
9.入队
Status EnQueue(SqQueue *Q,QElemType e){
//队列已满
if((Q->rear+1)%MAXSIZE == Q->front)
return ERROR;
//将元素e赋值给队尾
Q->data[Q->rear] = e;
//rear指针向后移动一位,若到最后则转到数组头部;
Q->rear = (Q->rear+1)%MAXSIZE;
或者
// Q->data[(Q->rear)%MAXSIZE] = e;
// Q->rear++
return OK;
}
10.出队
//若队列不空,则删除Q中队头的元素,用e返回值
Status DeQueue(SqQueue *Q,QElemType *e){
//判断队列是否为空
if (Q->front == Q->rear) {
return ERROR;
}
//将队头元素赋值给e
*e = Q->data[Q->front];
//front 指针向后移动一位,若到最后则转到数组头部
Q->front = (Q->front+1)%MAXSIZE;
return OK;
}
11.遍历
Status QueueTraverse(SqQueue Q){
int i;
i = Q.front;
while (i != Q.rear) {
printf("%d ",Q.data[i]);
i = (i+1)%MAXSIZE;
}
printf("\n");
return OK;
}
二、链式存储队列
链式队列的实现思想同顺序队列类似,只需创建两个指针(命名为 front 和 rear)分别指向链表中队列的头结点(没头结点的是首元节点)和队尾元素,现在的都是带头结点的

1.节点结构
#include <stdio.h>
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include "time.h"
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20 /* 存储空间初始分配量 */
typedef int Status;
typedef int QElemType; /* QElemType类型根据实际情况而定,这里假设为int */
结点结构
typedef struct QNode { /* 结点结构 */
QElemType data;
struct QNode *next;
}QNode,*QueuePtr;
typedef struct { /* 队列的链表结构 */
QueuePtr front,rear; /* 队头、队尾指针 */
}LinkQueue;
2.初始化队列 带头结点的

Status InitQueue(LinkQueue *Q){
//1. 头/尾指针都指向 头结点
Q->front = Q->rear = (QueuePtr)malloc(sizeof(QNode));
//2.判断是否创建新结点成功与否
if (!Q->front) {
return ERROR;
}
//3.头结点的指针域置空
Q->front->next = NULL;
return OK;
}
3.销毁队列

Status DestoryQueue(LinkQueue *Q){
//遍历整个队列,销毁队列的每个结点 借用Q->rear,省的用临时变量
//头节点也是个malloc开辟的,也需要释放
while (Q->front) {
Q->rear = Q->front->next;
free(Q->front);
Q->front = Q->rear;
}
return OK;
}
4.将队列置空, 只保留头结点

Status ClearQueue(LinkQueue *Q){
QueuePtr p,q;
Q->rear = Q->front;
p = Q->front->next;
Q->front->next = NULL;
//释放节点空间
while (p) {
q = p;
p = p->next;
free(q);
}
return OK;
}
5.判断队列是否为空
Status QueueEmpty(LinkQueue Q){
if (Q.front == Q.rear)
return TRUE;
else
return FALSE;
}
6.获取队列长度
int QueueLength(LinkQueue Q){
int i= 0;
QueuePtr p;
p = Q.front;
while (Q.rear != p) {
i++;
p = p->next;
}
return i;
}
7.入队

1.创建新节点s
2.rear-> = s
3.rear = s
Status EnQueue(LinkQueue *Q,QElemType e){
//为入队元素分配结点空间,用指针s指向;
QueuePtr s = (QueuePtr)malloc(sizeof(QNode));
//判断是否分配成功
if (!s) {
return ERROR;
}
//将新结点s指定数据域.
s->data = e;
s->next = NULL;
//将新结点插入到队尾
Q->rear->next = s;
//修改队尾指针
Q->rear = s;
return OK;
}
8.出队

1.获取首元结点p,即front->next
2.头节点front的next指向p的next,front->next = p->next
3.释放首元结点空间free(p)
Status DeQueue(LinkQueue *Q,QElemType *e){
QueuePtr p;
//判断队列是否为空;
if (Q->front == Q->rear) {
return ERROR;
}
//将要删除的队头结点暂时存储在p
p = Q->front->next;
//将要删除的队头结点的值赋值给e
*e = p->data;
//将原队列头结点的后继p->next 赋值给头结点后继
Q->front->next = p ->next;
//若队头就是队尾,则删除后将rear指向头结点.
if(Q->rear == p) Q->rear = Q->front;
free(p);
return OK;
}
9.获取队头元素
Status GetHead(LinkQueue Q,QElemType *e){
//队列非空
if (Q.front != Q.rear) {
//返回队头元素的值,队头指针不变
*e = Q.front->next->data;
return TRUE;
}
return FALSE;
}
10.遍历
Status QueueTraverse(LinkQueue Q){
if (*Q->front->next == NULL) return ERROR;
QueuePtr p;
p = Q.front->next;
while (p) {
printf("%d ",p->data);
p = p->next;
}
printf("\n");
return OK;
}