和栈相反,队列是一种先进先出(first in first out, 缩写为FIFO)的线性表。它只允许在表的一端进行插入,而另一端删除元素。除了栈和队列之外,还有一种限定性数据结构是双端队列(deque)。双端队列是限定插入和删除操作在表的两端进行的线性表。实际上在应有程序中远不及栈和队列有用。
和线性表类似,队列也可以有两种存储方式(线性表有顺序存储和链式存储两种方式)表示。用链表表示的队列简称为链队列。一个链队列显然需要两个分别指示队头和队尾的指针(分别称为头指针和尾指针)才能唯一确定。
队列的链式实现
和线性表的单链表一样,为了操作方便起见,我们也给链队列添加一个头节点,并令头指针指向头结点。由此,空的链队列的判决条件为头指针和尾指针均指向头节点。值的注意的是删除队列头元素算法中的特殊情况,一般情况下,删除队列头元素时仅需修改头节点的指针,但当队列中最后一个元素被删除后,队列尾指针也丢失,因此需要对队尾指针重新赋值(指向头节点)。
队列存储结构
typedef struct{
int val;
}QElemType;
typedef struct QNode{
QElemType data;
struct QNode *next;
}QNode, *QueuePtr;
typedef struct{
QueuePtr front;
QueuePtr rear;
}LinkQueue;
构造队列
void InitQueue(LinkQueue *Q)
{
Q->front = Q->rear = (QueuePtr)malloc(sizeof(QNode));
if (!Q->front)
{
exit(0);
}
Q->front->next = NULL;
}
销毁队列
void DestroyQueue(LinkQueue *Q)
{
while (Q->front)
{
Q->rear = Q->front->next;
free(Q->front);
Q->front = Q->rear;
}
}
清空队列
void ClearQueue(LinkQueue *Q)
{
while (Q->front->next)
{
Q->rear = Q->front->next->next;
free(Q->front->next);
Q->front->next = Q->rear->next;
}
free(Q->front->next);
Q->rear = Q->front;
}
判断空队列
int QueueEmpty(LinkQueue *Q)
{
int tmp = 0;
if (Q->front == Q->rear)
{
tmp = 1;
}
else
{
tmp = 0;
}
return tmp;
}
队列长度
int QueueLength(LinkQueue Q)
{
QueuePtr p = Q.front->next;
int tmp = 0;
while (p != Q.rear->next)
{
tmp++;
p = p->next;
}
return tmp;
}
队列首部
QElemType GetHead(LinkQueue Q)
{
if (Q.front == Q.rear)
{
exit(0);
}
return Q.front->next->data;
}
入队
void EnQueue(LinkQueue *Q, QElemType e)
{
QueuePtr p = (QueuePtr)malloc(sizeof(QNode));
if (!p)
{
exit(0);
}
if (QueueEmpty(Q))
{
Q->front->next = p;
}
p->data = e;
p->next = NULL;
Q->rear->next = p;
Q->rear = p;
}
出队
void DeQueue(LinkQueue *Q, QElemType *e)
{
QueuePtr p = Q->front->next;
if (Q->front == Q->rear)
{
exit(0);
}
*e = p->data;
Q->front->next = p->next;
if (Q->rear == p)
{
Q->rear = Q->front;
}
free(p);
}
队的遍历
void QueueTraverse(LinkQueue Q, void(*fp)(QElemType))
{
QueuePtr p = Q.front->next;
while (p != Q.rear->next)
{
fp(p->data);
p = p->next;
}
}
循环队列的实现
跟上面的队列类似,除了用一组地址连续的存储单元一次存放从队列头道队列尾的元素之外,尚需附设两个指针front和rear分别只是队列头元素及队列尾元素的位置。为了在C语言中描述方便起见,在此我们约定:初始化建空队列时,令front=rear=0,每当插入新的队列尾元素时,“尾指针增1”;每当删除队列头元素时,“头指针增1”。因此,在非空队列中,头指针始终指向队列头元素,为尾指针始终指向队列尾元素的下一个位置。