目录
一、队列的简介
队列:一种只允许在一端进行插入操作,在另一端进行删除操作的特殊线性表。(先进先出)
如图所示为队列的示意图:
队列的分类:
1、顺序队列:创建顺序队列需申请一块连续的内存空间(动态 / 静态申请),使用两个指针进行管理。一个指针 front 指向队头元素,一个指针 rear 指向队尾元素后一位置,即下一次入队的元素存储的位置。有两种出队操作,下面对这两种方式进行比较,了解其中优劣。
上述两种方法,操作步骤是相同的,只是队头指针的操作不同,通过示意图我们发现:
对于方法(1),每次出队,所有元素都需要向前移动一位,如果多次出队,就需要多次移动大量数据;
对于方法(2),我们可以很明显的发现,每出队一个数据,数列中就会有一个位置失去它的是有价值,比如说在上述情况下,我们再进队 F G ,而队列此时只有一个元素的位置,所以只有 F 可以实现入队,而 G 会因为队满而无法入队,事实上我们发现,队列并没有满,但是却无法入队,我们称之为假溢出。
2、循环队列:头尾相接的顺序队列。
我们发现循环队列解决了“假溢出”,需要注意的是判空与判满。
二、顺序队列
下面实现的顺序队列,使用动态开辟空间的方法实现,出队使用上述所说的第二种方法。
1、定义
typedef int DataType;
typedef struct QueueNode
{
DataType _data;
struct QueueNode* _next;
}QueueNode;
typedef struct Queue
{
QueueNode* _front;
QueueNode* _rear;
}Queue;
2、入队
static QueueNode* BuyQueueNode(DataType d)
{
QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));
assert(newNode);
newNode->_data = d;
newNode->_next = NULL;
return newNode;
}
void QueuePush(Queue* pq, DataType d)
{
assert(pq);
// 判断队列是否为空
if (pq->_front == NULL)
{
pq->_front = pq->_rear = BuyQueueNode(d);
}
else
{
QueueNode* rear = BuyQueueNode(d);
pq->_rear->_next = rear;
pq->_rear = rear;
}
}
3、出队
// 出队选择第二种方法,即队头不固定位置,通过动态实现顺序队列来避免假溢出,但会浪费一些空间
void QueuePop(Queue* pq)
{
QueueNode* next = NULL;
assert(pq);
next = pq->_front->_next;
free(pq->_front);
pq->_front = next;
}
4、其他接口
#include "Queue.h"
void QueueInit(Queue* pq)
{
assert(pq);
pq->_front = NULL;
pq->_rear = NULL;
}
void QueueDestory(Queue* pq)
{
QueueNode* cur = pq->_front;
assert(pq);
while (cur != NULL)
{
QueueNode* next = cur->_next;
free(cur);
cur = next;
}
pq->_front = NULL;
pq->_rear = NULL;
}
DataType QueueFront(Queue* pq)
{
assert(pq);
return pq->_front->_data;
}
int QueueEmpty(Queue* pq)
{
assert(pq);
return pq->_front == NULL ? 0 : 1; //空 0 非空 1
}
int QueueSize(Queue* pq)
{
int size = 0;
QueueNode* cur = NULL;
assert(pq);
cur = pq->_front;
while (cur)
{
size++;
cur = cur->_next;
}
return size;
}
三、循环队列
上面我们已经说了循环队列解决了“假溢出”的问题,我们在下面的定义中,只定义了队列最大可容纳的数据为6,实际上最大元素个数为5,循环队列中,始终有一个元素的位置用来让我们判断队空与队满。
1、定义
#define maxSize 6
typedef int DataType;
typedef struct CirQueue{
DataType* data;
int front;
int rear;
}CirQueue;
2、入队
void CirQueuePush(CirQueue* pcq, DataType d)
{
if (CirQueueFull(pcq))
{
printf("队列已满,无法入队数据\n");
}
else
{
pcq->data[pcq->rear + 1] = d;
pcq->rear = (pcq->rear + 1) % maxSize;
}
}
3、出队
void CirQueuePop(CirQueue* pcq)
{
if (!CirQueueEmpty(pcq))
{
printf("队列为空,无可出队数据\n");
}
else
{
pcq->front = (pcq->front + 1) % maxSize;
}
}
4、其他接口
void CirQueueInit(CirQueue* pcq)
{
pcq->data = (DataType*)malloc(sizeof(DataType)*maxSize);
assert(pcq->data);
pcq->front = 0;
pcq->rear = 0;
}
void CirQueueDestory(CirQueue* pcq)
{
free(pcq->data);
pcq->data = NULL;
}
DataType CirQueueFront(CirQueue* pcq)
{
assert(pcq);
return pcq->data[(pcq->front + 1) % maxSize];
}
int CirQueueFull(CirQueue* pcq)
{
assert(pcq);
return pcq->front == (pcq->rear + 1) % maxSize ? 1 : 0; // 满 1 不满 0
}
int CirQueueEmpty(CirQueue* pcq)
{
assert(pcq);
return (pcq->front == pcq->rear) ? 0 : 1; // 空 0 非空 1
}
int CirQueueSize(CirQueue* pcq)
{
if (CirQueueFull(pcq))
{
return maxSize - 1;
}
return pcq->rear - pcq->front > 0 ? pcq->rear - pcq->front : pcq->front - pcq->rear;
}