目录
1、队列的链式存储
队列的链式表示称为链队列 ,它实际上是一个同时带有队头指针和队尾指针的单链表。头指针指向队头结点。尾指针指向队尾结点,即单链表的最后一个结点。
图17.1 不带头结点的链式队列
队列的链式存储类型可描述为
//链式队列结点
typedef struct
{
ElemType data;
struct LinkNode *next;
}LinkNode;
//链式队列
typedef struct
{
LinkNode *front,*rear;
}LinkQueue;
当Q.front == NULL && Q.rear == NULL时u,链式队列为空。
出队时,首先判断队是否为空,若不空,则取出队头元素,将其从链表中华摘除,并让Q,front = Q.front->next;
入队时,建立一个新的结点,将该结点插入到链表的尾部,并让Q.rear = Q.rear->next。
从上述描述看出,出现了和顺序队列同样的问题,就是操作浪费空间(空间只能用一次),且耗时。
2、链式队列的基本操作
2.1、初始化
void InitQueue(LinkQueue &Q)
{
Q.front = Q.rear = (LinkNode *)malloc(sizeof(LinkNode));
Q.front->next = NULL;
}
2.2、判队空
bool IsEmpty(LinkQueue Q)
{
if(Q.front == Q.rear)
return true;
return false;
}
2.3、入队
void EnQueue(LinkQueue &Q,ElemType x)
{
LinkNode * node = (LinkNode *)alloc(sizeof(LinkNode));
node.data = x;
node.next == NULL;
Q.rear->next = node;
Q.rear = node; //切记最后要讲rear指针挪到新插入的结点上
node == NULL;
}
2.4、出队
//不带头结点的链式队列
bool DeQueue(LinkQueue &Q,ElemType &x)
{
if(Q.front == Q.rear)
return false;
LinkNode * DeNode = Q.front;
Q.front = Q.front->next;
x = Denode->data;
free(DeNode);
return true;
}
//带头结点的链式队列
bool DeQueue(LinkQueue &Q,ElemType &x)
{
if(Q.front == Q.rear)
return false;
LinkNode * DeNode = Q.front->next;
Q.front->next = DeNode ->next;
if(Q.rear == DeNode)
Q.rear = Q.front;
x = Denode->data;
free(DeNode);
return true;
}
3、双端队列
双端队列是指允许两端都可以进行入队和出队操作的队列。如图17.2所示。其元素的逻辑结构仍是线性结构。将队列的两端分别称为前端和后端,两端都可以入队和出队。
图17.2 双端队列
在双端队列进队时,前端进的元素排列在队列中后端进的元素的前面,后端进的元素排列在队列中前端进的元素的后面。
在双端队列出队时,无论是前端还是后端,先出的元素排在后出的元素的前面。
那么,如何由入序队列a,b,c,d得到出序队列d,c,a,b?
一种方法是后端先出队元素d,c,完了前端再出队元素a,b。
3.1、输出受限的双端队列
允许在一端进行插入和删除,但在另一端只允许插入的双端队列称为输出受限的双端队列,如图17.3 所示。
图17.3 输出受限的双端队列
3.2、输入受限的双端队列
允许在一端进行插入和删除,但另一端只允许删除的双端队列称为输入受限的双端队列,如图17.4所示
图17.4 输入受限的双端队列
你,总要埋头去做一些事情,不是吗