请结合我的另一篇文章食用 数据结构与算法–栈.
基本定义
队列是一种先进先出的线性表,只允许在一端进行插入,而在另一端进行删除。
参考完栈的实现,很容易发现,队列和栈的实现基本相同
我们这里只是简单介绍队列的基本操作和实现
基本操作
InitQueue(&Q);//队列的初始化
DestroyQueue(&Q);//队列的销毁
QueueEmpty(Q);//队列是否为空
QueueLength(Q);//队列长度
GetHead(Q,&e);//得到队首元素
EnQueue(&Q,e);//入队
DeQueue(&Q);//出队
QueueTraverse(Q,visit());//遍历
栈的表达和实现
顺序存储结构
用一组地址连续的存储单元依次存放队头到队尾的元素
类似栈实现的base和top指针,这里队列的front指针指向队列第一个元素,rear指向队列最后一个元素的下一个位置。
front = NULL 表示队列不存在;front = rear 表示空队列;rear = MAXSIZE表示队满
//简单介绍
元素入队:++rear;
元素出队:++front;
很容易看出,当出队的时候,头部存储空间无法再次使用,导致空间使用率下降,所以我们可以使用循环队列(实际只是灵活运用空间编号)
- front指向队头,rear指向队尾下一个元素
- front = rear表示空队列
- 元素入队:rear = (rear+1)%MAXSIZE;
- 元素出队:front = (front+1)%MAXSIZE;
但是通过以上定义我们可以发现一个bug:当栈为空时front = rear,但是当栈满时也是front = rear。
所以为解决以上问题,我们规定,在循环队列中,front和rear之间总是空出来一个空间.(实际上就是当rear下一个位置为front时我们就及时刹车,设置队满,不再允许元素入队)
- front指向队首,rear指向队尾下一个位置。
- 空队列:front = rear
- 满队列:(rear+1)%MAXSIZE = front
- 元素入队:rear = (rear+1)%MAXSIZE;
- 元素出队:front = (front+1)%MAXSIZE;
- 元素个数:cnt = (rear - front + MAXSIZE)%MAXSIZE;(C里面取模允许为负,所以我们要加上MAXSIZE)
链式存储结构
队列具有只是队头和队尾的指针(头指针和尾指针)
同时,队列具有头结点
头指针front指向第一个元素的前一个元素,初始化指向头结点
尾指针rear指向最后一个元素,初始化指向头结点
空队列:Q.front = Q.rear
//以下为伪代码,具体代码自行编写,可参考栈的实现
typedef struct QNode
{
QElemType data;
struct QNode *next;
} QNode, *QueuePtr;
typedef struct
{
QueuePtr front; // 队头指针
QueuePtr rear; // 队尾指针
}LinkQueue;
//元素入队(也就是队尾插入元素)
Status EnQueue ( LinkQueue &Q, QElemType e )
{
p = ( QueuePtr ) malloc ( sizeof(QNode));
if ( !p )
exit (OVERFLOW);
p->data = e;
p->next = NULL; //申请新结点
Q.rear->next = p;
Q.rear = p; //插入在队尾
return OK;
}
//元素入队(也就是队首删除元素)
Status DeQueue ( LinkQueue &Q ,QElemType &e )
{
if ( Q.front == Q.rear )
return ERROR;
p = Q.front->next;
e = p->data; //取第一个结点
Q.front->next = p->next; //删除第一个结点
if ( Q.rear == p ) //若需要删除的队头结点就是尾结点,这一步很重要
Q.rear = Q.front;
free ( p );
return OK;
}