一、基础知识
- 队列的定义:一种特殊的线性表,只允许在一端进行插入数据操作,在另一端进行删除数据操作。进行插入操作的一端称为队尾,进行删除操作的一端称为队头。
- 原则:先进先出 或 后进后出
- 实现:数组队 和 链队
数组队:尾插实现简单,但头删效率不高
链队:尾插只要找到尾结点就🆗,头删简单
总结:
结合数组栈和链栈的优缺点,最好采用链队。因为需要知道链队的头与尾,所以还需要定义一个结构体包含其头与尾。(具体看接口)
二、接口
结构体
typedef int DataType;
typedef struct QueueNode
{
DataType data;
QueueNode* next;
}QueueNode;
typedef struct Queue
{
QueueNode* head;
QueueNode* tail;
}Queue;
2.1 初始化
//初始化
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
}
2.2 销毁
//销毁
void QueueDestroy(Queue* pq)
{
assert(pq);
//第一层删除:删除链表中的结点
QueueNode* cur = pq->head;
while (cur)
{
QueueNode* next = cur->next;
free(cur);
cur = next;
}
//第二层删除:将结构体中的head和tail置空
pq->head = pq->tail = NULL;
}
注意:
Queue
结构体与QueueNode
结构体为嵌套结构,所以先删除QueueNode
再删除Queue
2.3 入队
//入队
void QueuePush(Queue* pq, DataType x)
{
assert(pq);
//新建结点
QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));
newNode->data = x;
newNode->next = NULL;
//队列中没有结点的情况
if (pq->head == NULL)
{
pq->head = pq->tail = newNode;
}
else
{
pq->tail->next = newNode;//tail与新结点链接
pq->tail = newNode;//更新tail
}
}
2.4 出队
//出队
void QueuePop(Queue* pq)
{
assert(pq);
assert(pq->head);//队为空的情况
QueueNode* next = pq->head->next;//标记头的下一个结点
free(pq->head);
pq->head = next;
//如果此时队为空,head随next置空,但tail成为了野指针
if (pq->head == NULL)
{
pq->tail = NULL;
}
}
2.5 取队头元素
//取队头元素
DataType QueueFront(Queue* pq)
{
assert(pq);
assert(pq->head);
return pq->head->data;
}
2.6 取队尾元素
//取对尾元素
DataType QueueBack(Queue* pq)
{
assert(pq);
assert(pq->head);
return pq->tail->data;
}
2.7 队的大小
//队的大小
int QueueSize(Queue* pq)
{
assert(pq);
assert(pq->head);
QueueNode* cur = pq->head;
int n = 0;
while (cur)
{
++n;
cur = cur->next;
}
return n;
}
对于计算队的大小的方式还有一种是在
Queue
中加入int size
;初始化为0,若入队++size
,若出队--size
,得到队大小直接return pq->size
2.8 判断队是否为空
//判断队列是否为空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL;
}