一、队列的定义
队列(queue)是只允许在一端进行插入操作,在另一端进行删除操作的线性表,允许插入的一端称为队尾,允许删除的一端称为队头,队列的特点是先进先出(First In First Out)
向队列中插入新的数据元素称为入队。
从队列中删除队头元素称为出队。
二、 队列的顺序存储结构
顺序队列
用一组地址连续的存储单元,依次存放从队头到队尾的数据元素,称为顺序队列。实现顺序队列需要设两个指针:队头指针(front)和队尾指针(rear),分别指向队头元素和队尾元素。
如果在插入E的基础上再插入元素F,将会插入失败。因为rear==MAXSIZE,尾指针已经达到队列的最大长度。但实际上队列存储空间并未全部被占满,这种现象叫做“假溢出”。
通过上图可以发现队头出队、对尾入队造成了数组前面的空间未被利用而出现假溢出。
为了解决“假溢出”现象,使得队列的存储空间得到充分利用,一个非常巧妙的方法就是将顺序队列的数组看成一个头尾相接的循环结构。
循环队列
现在队满了,但是队头指针和队尾指针相等(队空的时候也是这样)。
那么该怎么判断队空还是队满?
两种解决方案
- 设置一个计数器,开始的时候为0,当有元素入队时+1,有元素出队时-1,值为MAXSIZE时队满
- 保留一个元素空间,当队尾指针指的空单元的下一个单元是队头指针所指单元是为对满
队满的条件(Queue.rear+1)%MAXSIZE==Queue.front
队空的条件Queue.rear=Queue.front
循环队列结构
#define MAXSIZE 20
/*循环队列的存储结构*/
typedef struct Queue
{
int data[MAXSIZE];
int front; //头指针
int rear; //尾指针
}Queue;
循环队列相关操作
- 初始化空队列
int InitSeQueue(Queue* queue);
- 获得队列长度
int GetLength(Queue* queue);
- 判空
bool isEmpty(Queue* queue);
- 判满
bool isFull(Queue* queue);
- 入队操作
int EnterQueue(Queue* queue, int e);
- 出队操作
int ExitQueue(Queue* queue, int e);
// **初始化空队列**
void InitSeQueue(Queue* queue)
{
queue->front = 0;
queue->rear = 0;
return 0;
}
//**获得队列长度**
int GetLength(Queue* queue)
{
return (queue->rear-queue->front+MAXSIZE)%MAXSIZE;
}
//**判空**
bool isEmpty(Queue* queue)
{
return queue->front==queue->rear;
}
//**判满**
bool isFull(Queue* queue)
{
return (queue->rear+1)%MAXSIZE==queue->front;
}
//**入队**
void EnterQueue(Queue* queue, int e)
{
if (isFull(queue))
{
printf("队列满了\n");
return;
}
else
{
queue->data[queue->rear] = e;
queue->rear = (queue->rear + 1) % MAXSIZE;//求模,rear的值就在[0,MAXSIZE-1]循环
}
}
//**出队**
void ExitQueue(Queue* queue, int*e)
{
if (isEmpty(queue))
{
printf("已经是空队列了\n");
return;
}
else
{
*e = queue->data[queue->front];
queue->front = (queue->front + 1) % MAXSIZE;//注意不要写成(queue->front - 1)
}
}
测试结果
第一次出队的时候front由0变成了1
6准备入队的时候rear=0,fornt=1,满足队满条件(Queue.rear+1)%MAXSIZE==Queue.front
三、队列的链式存储结构
链队列由单链表组成,队头指针指向链表的头结点,队尾指针指向尾节点。空队列时队头指针和队尾指针都指向头节点。
链队列是限制仅在表头进行删除操作和表尾进行插入操作的单链表。链队的操作实际上是单链表的操作,只不过是出队在表头进行,入队在表尾进行。
链队列结构
/*结点结构*/
typedef struct Node
{
int data;
struct Node *next;
}Node;
/*链队列结构*/
typedef struct LinkQueue
{
Node* front,rear;//队头、队尾指针
}LinkQueue;
链式队列的相关操作
- 初始化空队列
void InitLinkQueue(LinkQueue* LinkQ)
- 判空
bool isEmpty(LinkQueue* LinkQ)
- 入队操作
void EnterLinkQueue(LinkQueue* LinkQ, int x)
- 出队操作
void ExitLinkQueue(LinkQueue* LinkQ, int* x)
- 遍历
void Print(LinkQueue* LinkQ)
//**初始化链队列**
void InitLinkQueue(LinkQueue* LinkQ)
{
Node* head = malloc(sizeof(Node));
if (LinkQ != NULL && head != NULL)
{
LinkQ->front = LinkQ->rear = head;
head->next = NULL;
}
}
//**判空**
bool isEmpty(LinkQueue* LinkQ)
{
return LinkQ->front == LinkQ->rear;
}
//**入队**
void EnterLinkQueue(LinkQueue* LinkQ, int x)
{
Node* node = malloc(sizeof(Node));
node->data = x;
node->next = NULL;
LinkQ->rear->next = node;
LinkQ->rear=node;
}
//**出队**
void ExitLinkQueue(LinkQueue* LinkQ, int* x)
{
if (isEmpty(LinkQ))
return;
Node* node = malloc(sizeof(Node));
//保留删除结点的信息
node = LinkQ->front->next;
*x = LinkQ->front->data;
//建立新联系
LinkQ->front->next = node->next;
//如果队尾出队了,那么就是空队
if (LinkQ->rear == node)
LinkQ->front = LinkQ->rear;
free(node);
}
//**遍历**
void Print(LinkQueue* LinkQ)
{
Node* node = LinkQ->front->next;
while (node)
{
if (node == LinkQ->rear)
{
printf(" rear%d,node%d\n", LinkQ->rear->data, node->data);
return;
}
printf("%2d", node->data);
node = node->next;
}
printf("\n");
}