设想你在超市排队付款,你将从队尾进入,从队头离开--这便是一个队列。
在《C Primer Plus》一书中,队列的定义是“一种’先进先出‘(first in first out,即FIFO)的数据形式”。队列(queue)实际上是具有两个特殊属性的链表。1.新项只能从队列的末尾添加;2只能从链表的开头移除项。
明白了这些后,我们实际上就可以把队列想象成一个环来帮助理解,我们将需要一个正常的链表Node结构体,同时需要额外一个Queue的结构体,里面存放指向队列的头指针和尾指针。
我们还需要什么呢?哦对了,一个队伍它所容纳的人数有限,这样才可控。类比一下队列,我们的队列需要一个最大容限。我们一般做的队列是一个小型的,这样方便我们动态分配内存(当然大型的并不是没有,这里我们不展开讨论)。那么我们又该如何判断队列是否已满呢?常规的方法是有两个:1.利用tail和head的差值进行计算;2.在Queue结构体中,放入int items来记录项数,在每次的添加Node的同时,让items自增,并在下次添加前与最大容量比较。
这里我们仍然选择着重讨论第二种,下面我们来看一下代码的实现。(摘自《C Primer Plus》)
queue.h文件:
#ifndef _QUEUE_H_
#define _QUEUE_H_
#include <stdbool.h>
//在这里插入Item类型的定义
typedef int Item;
// typedef struct item
// {
// int gumption;
// int charisma;
// }item;
#define MAXQUEUE 10
typedef struct node
{
Item item;
struct node * next;
}Node;
typedef struct queue
{
Node * front;//指向队列首项的指针
Node * rear;//指向队列尾项的指针
int items;//队列中的项数
}Queue;
//操作:初始化队列
//前提条件:pq指向一个队列
//后置条件:队列被初始化为空
void InitializeQueue(Queue * pq);
//操作:检查队列是否已满
//前提条件:pq指向之前被初始化的队列
//后置条件:如果队列已满则返回true,否则返回false
bool QueueIsFull(const Queue * pq);
//操作:检查队列是否为空
//前置条件:pq指向之前被初始化的队列
//后置条件:如果队列为空则返回true,否则返回false
bool QueueIsEmpty(const Queue *pq);
//操作:确定队列中的项数
//前提条件:pq指向之前被初始化的队列
//后置条件:返回队列中的项数
int QueueItemCount(const Queue * pq);
//操作:在队列末尾添加项
//前置条件:pq指向之前被初始化的队列;item是要被添加在队列末尾的项
//后置条件:如果队列不为空,item将被添加在队列的末尾,该函数返回true;否则,队列不改变,该函数返回false
bool EnQueue(Item item,Queue *pq);
//操作:从队列的开头删除项
//前提条件:pq指向之前被初始化的队列
//后置条件:如果队列不为空,队列首端的item将被拷贝到*pitem中并被删除,且函数返回true;
// 如果该操作使得队列为空,则重置队列为空
// 如果队列在操作前为空,该函数返回false
bool DeQueue (Item *pitem, Queue *pq);
//操作:清空队列
//前提条件:pq指向之前被初始化的队列
//后置条件:队列被清空
void EmptyTheQueue(Queue * pq);
#endif
queue.c文件:
#include <stdio.h>
#include <stdlib.h>
#include "queue.h"
//局部函数
static void CopyToNode(Item item, Node * pn);
static void CopyToItem(Node *pn,Item *pi);
void InitializeQueue(Queue *pq)
{
pq->front = pq->rear = NULL;
pq->items = 0;
}
bool QueueIsFull(const Queue *pq)
{
return pq->items == MAXQUEUE;
}
bool QueueIsEmpty(const Queue *pq)
{
return pq->items == 0;
}
int QueueItemCount(const Queue *pq)
{
return pq->items;
}
bool EnQueue(Item item,Queue *pq)
{
Node *pnew;
if(QueueIsFull(pq))
return false;
pnew = (Node *)malloc(sizeof(Node));
if(pnew == NULL)
{
fprint(stderr,"Unable to allocate memory!\n");
exit(1);
}
CopyToNode(item,pnew);
pnew->next=NULL;
if(QueueIsEmpty(pq))
pq->front = pnew;//项位于队列的顶端
else
pq->rear->next=pnew;//链接到队列的尾端
pq->rear = pnew;//记录队列尾端的位置
pq->items++;
return true;
}
bool DeQueue(Item *pitem, Queue *pq)
{
Node *pt;
if(QueueIsEmpty(pq))
return false;
CopyToItem(pq->front, pitem);
pt = pq->front;
pq->front = pq->front->next;
free(pt);
pq->items--;
if(pq->items == 0)
pq->rear = NULL;
return true;
}
//清空队列
void EmptyTheQueue(Queue *pq)
{
Item dummy;
while (!QueueIsEmpty(pq))
DeQueue(&dummy,pq);
}
//局部函数
static void CopyToNode(Item item,Node *pn)
{
pn->item = item;
}
static void CopyToItem(Node *pn, Item *pi)
{
*pi = pn->item;
}