目录
一、队列的原理
队列,又称为伫列(queue),计算机科学中的一种抽象资料型别,是先进先出(FIFO, First-In-First-Out)的线性表。在具体应用中通常用链表或者数组来实现。队列只允许在后端(称为rear)进行插入操作,在前端(称为front)进行删除操作。
队列的操作方式和堆栈类似,唯一的区别在于队列只允许新数据在后端进行添加。
队列与栈类似,但是队列遵循先进先出原则,它在队尾入数据,在队头出数据
同时队列也不能遍历,如果遍历同样会打乱队列的结构,
队列·一般用链表来实现,因为队列对数据的操作均在队头,单链表可以很快找到队头,而数组在头部插入或者删除数据时,需要移动数据,这个操作的时间复杂度是O(N)
而链表是O(1)
二、队列的实现
1.队列的定义
typedef int QDataType;
typedef struct QNode
{
struct QNode* next;
QDataType data;
}QNode;
我们先定义队列节点,因为是用单链表来实现,节点的定义与单链表类似
同时我们的队列要支持,取队首的元素和取队尾的元素
所以我们需要单独定义head指针和tail指针
typedef struct Queue
{
QNode* head;
QNode* tail;
}Queue;
2.队列的初始化
队列初始化很简单
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
}
3.入队列
入队列是我们需要创建新节点,然后将新节点头插到链表
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
QNode* newNode = (QNode*)malloc(sizeof(QNode));
if (newNode == NULL)
{
printf("malloc fail\n");
exit(-1);
}
newNode->data = x;
newNode->next = NULL;
if (pq->head == NULL)
{
pq->head = pq->tail = newNode;
}
else
{
pq->tail->next = newNode;
pq->tail = newNode;
}
}
4.出队列
出队列我们需要先判断队列是否为空,如果为空就直接报错
队列不为空时,我们需要讨论队列中有一个元素和多个元素
如果有一个元素,就让head和tail指向NULL
不为空就进行头删,然后就可以了
void QueuePop(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
QNode* next = pq->head->next;
if (next == NULL)
{
free(pq->head);
pq->head = pq->tail = NULL;
}
else
{
free(pq->head);
pq->head = next;
}
}
5.获取队列头部元素
我们直接返回head指针的data就可以
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->head->data;
}
6.获取队列队尾元素
与获取头部元素类似
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->data;
}
7.检测队列是否为空
是否为空就是看头指针是否指向NULL
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
}
8.队列元素个数·
我们只需要遍历链表就可以知道元素个数·
int QueueSize(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
int size = 0;
while (cur)
{
cur = cur->next;
++size;
}
return size;
}
9.销毁队列
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
}