队列的的概念
队列是一种特殊的线性表,特殊之处在于它只允许在表的头部进行删除操作,而在表的尾部进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。
队列的特点
- 先进先出 :这是队列最大的特点,队列中所有的元素都遵循先进先出的原则进行管理数据,最先入队列的一定会最先出队列。
- 受限访问:队列操作数据时,只能对队头或者队尾进行操作。入队(插入数据)只会在队尾进行,出队(删除数据)只会在对头进行。
- 高效:进行删除和插入数据,最坏情况下的时间复杂度是O(1)。
队列的接口实现
队列可以使用数组和链表来实现,但是链表实现起来更清晰。
队列的结构
c
typedef int QUEDATATYPE;
typedef struct QueueNode
{
QUEDATATYPE data;
struct QueueNode* next;
}QUENODE;
但是这样有个问题,我每次插入都要找尾节点,这样就太慢了,所以我们就用两个指针来解决这个问题,一个指针指向队列的头节点,一个用来指向队列的尾节点。
c
typedef int QUEDATATYPE;
typedef struct QueueNode
{
QUEDATATYPE data;
struct QueueNode* next;
}QUENODE;
typedef struct Queue
{
QUENODE* phead;
QUENODE* ptail;
int size;
}Queue;
队列的初始化
c
//初始化队列
void QueueInit(Queue* pq)
{
assert(pq);
pq->phead = pq->ptail = NULL;
pq->size = 0;
}
入队
入队操作在尾部进行
这里有有两个情况,队列为空与非空。
- 为空的话,就直接将新节点赋给
phead
和ptail
。 - 非空,将
ptail
的next
指针指向新节点,再更新ptail
。
c
//入队
void QueuePush(Queue* pq, QUEDATATYPE x)
{
assert(pq);
if (pq->phead == NULL)
{
QUENODE* Node = (QUENODE*)malloc(sizeof(QUENODE));
if (Node == NULL)
{
perror("malloc fail");
exit(1);
}
Node->data = x;
Node->next = NULL;
pq->phead = pq->ptail = Node;
}
else
{
QUENODE* Node = (QUENODE*)malloc(sizeof(QUENODE));
if (Node == NULL)
{
perror("malloc fail");
exit(1);
}
Node->data = x;
Node->next = NULL;
pq->ptail->next = Node;
pq->ptail = Node;
}
pq->size++;
}
出队
出队操作在队头进行
出队同样也有两种情况,只剩下一个节点和多个节点。
- 只有一个节点:也就是只有头节点了,直接将头节点释放掉就好了。
- 多个节点:将头节点释放,更新头节点
c
//出队
void QueuePop(Queue* pq)
{
assert(pq && pq->size > 0);
if (pq->phead->next == NULL)
{
free(pq->phead);
pq->phead = pq->ptail = NULL;
}
else
{
QUENODE* tmp = pq->phead;
pq->phead = pq->phead->next;
free(tmp);
tmp = NULL;
}
pq->size--;
}
获取队头元素
c
// 获取队头元素
QUEDATATYPE QueueHead(Queue* pq)
{
assert(pq);
return pq->phead->data;
}
判空
c
//判空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->size == 0;
}
获取栈中有效元素个数
c
// 获取栈中有效元素个数
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
销毁队列
c
//销毁队列
void QueueDestroy(Queue* pq)
{
QUENODE* tmp = pq->phead;
while (tmp)
{
pq->phead = pq->phead->next;
free(tmp);
tmp = pq->phead;
}
pq->phead = pq->ptail = NULL;
pq->size = 0;
}
完整代码
Queue.h
c
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int QUEDATATYPE;
typedef struct QueueNode
{
QUEDATATYPE data;
struct QueueNode* next;
}QUENODE;
typedef struct Queue
{
QUENODE* phead;
QUENODE* ptail;
int size;
}Queue;
//初始化队列
void QueueInit(Queue* pq);
//入队
void QueuePush(Queue* pq, QUEDATATYPE x);
//出队
void QueuePop(Queue* pq);
// 获取队头元素
QUEDATATYPE QueueHead(Queue* pq);
//判空
bool QueueEmpty(Queue* pq);
// 获取栈中有效元素个数
int QueueSize(Queue* pq);
//销毁队列
void QueueDestroy(Queue* pq);
Queue.c
c
#include"Queue.h"
//初始化队列
void QueueInit(Queue* pq)
{
assert(pq);
pq->phead = pq->ptail = NULL;
pq->size = 0;
}
//入队
void QueuePush(Queue* pq, QUEDATATYPE x)
{
assert(pq);
if (pq->phead == NULL)
{
QUENODE* Node = (QUENODE*)malloc(sizeof(QUENODE));
if (Node == NULL)
{
perror("malloc fail");
exit(1);
}
Node->data = x;
Node->next = NULL;
pq->phead = pq->ptail = Node;
}
else
{
QUENODE* Node = (QUENODE*)malloc(sizeof(QUENODE));
if (Node == NULL)
{
perror("malloc fail");
exit(1);
}
Node->data = x;
Node->next = NULL;
pq->ptail->next = Node;
pq->ptail = Node;
}
pq->size++;
}
//出队
void QueuePop(Queue* pq)
{
assert(pq && pq->size > 0);
if (pq->phead->next == NULL)
{
free(pq->phead);
pq->phead = pq->ptail = NULL;
}
else
{
QUENODE* tmp = pq->phead;
pq->phead = pq->phead->next;
free(tmp);
tmp = NULL;
}
pq->size--;
}
// 获取队头元素
QUEDATATYPE QueueHead(Queue* pq)
{
assert(pq);
return pq->phead->data;
}
//判空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->size == 0;
}
// 获取栈中有效元素个数
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
//销毁队列
void QueueDestroy(Queue* pq)
{
QUENODE* tmp = pq->phead;
while (tmp)
{
pq->phead = pq->phead->next;
free(tmp);
tmp = pq->phead;
}
pq->phead = pq->ptail = NULL;
pq->size = 0;
}