队列的定义
队列(queue)是一种先进先出(Fisrt in First Out,FIFO)的线性表,它只允许在表的一端进行插入,而在另一端删除元素。在队列中,允许插入的一段称为队尾(rear),允许删除的一端则称为队头(front)。假设队列为区(a1,a2,…an),那么a1就是队头元素,an就是队尾元素。队列中的元素按照a1,a2,…an的顺序进入,退出队列也按照这个顺序依次退出,也就是说,只有在a1,a2,…an-1都离开队列之后,an才能退出队列。、
队列的顺序结构实现
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#define MAXSIZE 100
typedef struct Queue {
int data[MAXSIZE];
int front;
int rear;
}queue;
队列的顺序结构实现-初始化
void initQueue(queue* Q)
{
Q->front = 0;
Q->rear = 0;
}
队列的顺序结构实现-判断是否为空
int isEmpty(queue* Q)
{
//注意判断条件是队头是否等于队尾!!!
//为什么不能是队头是否等于0,在后面会提到
if (Q->front == Q->rear)
{
cout << "空的" << endl;
return 1;
}
else
{
return 0;
}
}
队列的顺序结构实现-出队
int delqueue(queue* Q)
{
//判断是否为空
if (Q->front == Q->rear)
{
return 0;
}
int e = Q->data[Q->front];
Q->front++;
return e;//返回出队值
}
这里可以看到,出队就是将front自加使队头的下一个元素称为新队头,这也是为什么在判断队列是否为空时条件是队头队尾是否相等,因为在有元素出队后,队头已经不是0。
队列的顺序结构实现-入队和调整队列
int queueFull(queue* Q)
{
//如果队头大于0,说明队列中还有空间,只是队尾已经到达上限
//所以我们需要调整队伍,使整体向前移动,占满队头处,留出队尾处
if (Q->front > 0)
{
int step = Q->front;//队头距离数组下标0处的距离
for (int i = Q->front;i <= q->rear;i++)
{
Q->data[i - step] = Q->data[i];
}//全部元素向前移动step步
Q->front = 0;
Q->rear = Q->rear - step;
return 1;//返回1表示队列未满
}
else
{
cout << "真的满了" << endl;
return 0;//返回0表示队列已满
}
}
int enterQueue(queue* Q, int e)
{
//先判断队列是否已满
if (Q->rear >= MAXSIZE)
{
if (!queueFull(Q))
{
return 0;
}
}
Q->data[Q->rear] = e;
Q->rear++;
return 1;
}
这里需要强调,当rear等于队列上限时并不代表队列已满,因为front有可能不等于0,也就是说在队头之前还有空间,这时就需要调整队列,空出队尾,占满队头。
栈的顺序结构实现-获取队头数据
int getHead(queue* Q, int* e)
{
if (Q->front == Q->rear)
{
cout << "空的" << endl;
return 0;
}
*e = Q->data[Q->front];
return 1;
}
栈的顺序结构实现-动态内存分配
typedef struct Queue {
int *data;
int front;
int rear;
}queue;
queue* initQueue()
{
queue* q = new queue;
q->data = new int[MAXSIZE];
q->front = 0;
q->rear = 0;
return q;
}
在堆内存中开辟空间存储队列。
队列的顺序结构实现-循环队列
普通队列中,当队尾达到上限后,我们需要将每个元素都移动一遍来空出空间,这非常的复杂,我们可以通过循环队列来解决这一问题。
int circleEnterQueue(queue* Q, int e)
{
if ((Q->rear + 1) % MAXSIZE == Q->front)
{
cout << "满了" << endl;
return 0;
}
Q->data[Q->rear] = e;
Q->rear = (Q->rear + 1) % MAXSIZE;
return 1;
}
通过取模运算,在队尾已满时进行入队操作时就不需要调整队列了,新元素会被添加到数组下标为0的位置,当数组真正被填满时,才不能继续入队。
出队
int circleDelQueue(queue* Q, int* e)
{
if (Q->front == Q->rear)
{
cout << "空的" << endl;
return 0;
}
*e = Q->data[Q->front];
Q->front = (Q->front + 1) % MAXSIZE;
return 1;
}
队列的链式结构实现
队列的链式结构体
typedef struct queueNode {
int data;
struct queueNode* next;
}queueNode;
typedef struct {
queueNode* front;
queueNode* rear;
}queue;
相较于链表,队列的链式结构多出了一个结构体用于存储指向队头和队尾的两个指针。
队列的链式结构实现-初始化
queue* initQueue()
{
queue* q = new queue;
queueNode* node = new queueNode;
node->data = 0;
node->next = NULL;
q->front = node;
q->rear = node;
return q;
}
队列的链式结构实现-入队
void enterQueue(queue* q, int e)
{
queueNode* node = new queueNode;
node->data = e;
node->next = NULL;
q->rear->next = node;
q->rear = node;
//使用尾插法入队,队尾是rear,队头是头节点的下一节点即front->next
}
队列的链式结构实现-出队
int delQueue(queue* q, int* e)
{
queueNode* node = q->front->next;
*e = node->data;
q->front->next = node->next;
if (q->rear == node)
{
q->rear = q->front;
}
delete node;
return 1;
}
使用头删法出队,符合先进先出规则。
队列的链式结构实现-获取队头元素
int isEmpty(queue* q)
{
if (q->front == q->rear)
{
return 1;
}
else
{
return 0;
}
}
int getFront(queue* q)
{
if (isEmpty(q))
{
cout << "空的" << endl;
return 0;
}
return q->front->next->data;
}