(C语言)手撕数据结构之——队列
Posted waywt1
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(C语言)手撕数据结构之——队列相关的知识,希望对你有一定的参考价值。
目录
队列的概念及结构
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out)。
入队列:进行插入操作的一端称为队尾。
出队列:进行删除操作的一端称为队头。
队列的实现方式
实现队列有两种方式:1.用数组实现,2.用链表实现。
数组队列
缺点:元素出队列时需要将后面的数据向前面挪,效率比较低。
链式队列
在队列中保存指向队头队尾的两个指针,出队时只需将指向队头的指针指向原队头的下一个,入队时直接在队尾的后面入即可
故使用链表的结构实现会更优一点。
链式队列的实现
首先创建该队列中单个元素的结构体,然后创建一个队列结构体,包含指向头、尾两个指针。
typedef int QDataType;
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QNode;
typedef struct Queue
{
QNode* head;
QNode* tail;
}Queue;
下面给出需要实现的接口:
//初始化队列
void QueueInit(Queue* pq);
//入队列
void QueuePush(Queue* pq, QDataType x);
//出队列
void QueuePop(Queue* pq);
//获取队列头部元素
QDataType QueueFront(Queue* pq);
//获取队列队尾元素
QDataType QueueBack(Queue* pq);
//获取队列中有效元素个数
int QueueSize(Queue* pq);
//检测队列是否为空,如果为空返回非零结果,如果非空返回0
bool QueueEmpty(Queue* pq);
//销毁队列
void QueueDestroy(Queue* pq);
初始化队列
队列初始化只需将指向头、尾的两个指针指向空即可。
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
}
入队列
首先申请空间创建该元素,如果队列中无元素,则将该元素作为队列的头和尾;如果队列中有元素,则直接将该元素连接到队列的尾处,并将队列的尾指针指向该元素。
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->tail == NULL)
{
pq->head = pq->tail = newNode;
}
else
{
pq->tail->next = newNode;
pq->tail = newNode;
}
}
出队列
出队列时先检测队列中是否有元素,若队列中无元素,则应让程序直接报错。
有元素时分为一个或多个元素:
一个元素:直接释放该节点,并将原队列中的头、尾指针指向空。
多个元素:先保存头指针指向节点的下一个节点,然后释放头节点,并将头指针指向原保存值。
void QueuePop(Queue* pq)
{
assert(pq);
assert(pq->head);//若队列为空,无元素可出队列,直接报错
//1.一个元素
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = pq->tail = NULL;
}
//2.多个元素
else
{
QNode* next = pq->head->next;
free(pq->head);
pq->head = next;
}
}
获取队列头部元素
获取元素时先检测队列是否有元素,若无元素则直接报错,有元素则返回头指针指向节点的数据。
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(pq->head);
return pq->head->data;
}
获取队列尾部元素
与获取队头元素相类似。
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(pq->tail);
return pq->tail->data;
}
获取队列中有效元素个数
从队头开始遍历整个队列并计数即可,遍历时应创建一个新的变量进行遍历,保证不改变头指针。
int QueueSize(Queue* pq)
{
assert(pq);
int size = 0;
QNode* cur = pq->head;
while (cur)
{
size++;
cur = cur->next;
}
return size;
}
检测队列是否为空
如果为空返回非零结果,如果非空返回0
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL;
}
销毁队列
队列中每个元素都为新开辟的节点,故需要逐个销毁。将所有节点销毁完后将头、尾指针指向空。
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;
}
实现队列的全部代码
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#include <stdlib.h>
typedef int QDataType;
typedef struct QueueNode
{
QDataType data;
struct QueueNode* next;
}QNode;
typedef struct Queue
{
QNode* head;
QNode* tail;
}Queue;
//初始化队列
void QueueInit(Queue* pq);
//队尾入
void QueuePush(Queue* pq, QDataType x);
//队头出
void QueuePop(Queue* pq);
//获取队列头部元素
QDataType QueueFront(Queue* pq);
//获取队列队尾元素
QDataType QueueBack(Queue* pq);
//获取队列中有效元素个数
int QueueSize(Queue* pq);
//检测队列是否为空,如果为空返回非零结果,如果非空返回0
bool QueueEmpty(Queue* pq);
//销毁队列
void QueueDestroy(Queue* pq);
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
}
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->tail == NULL)
{
pq->head = pq->tail = newNode;
}
else
{
pq->tail->next = newNode;
pq->tail = newNode;
}
}
void QueuePop(Queue* pq)
{
assert(pq);
assert(pq->head);
//1.一个
//2.多个
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = pq->tail = NULL;
}
else
{
QNode* next = pq->head->next;
free(pq->head);
pq->head = next;
}
}
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(pq->head);
return pq->head->data;
}
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(pq->tail);
return pq->tail->data;
}
int QueueSize(Queue* pq)
{
assert(pq);
int size = 0;
QNode* cur = pq->head;
while (cur)
{
size++;
cur = cur->next;
}
return size;
}
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL;
}
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;
}
测试用例
void TestQueue()
{
Queue q;
QueueInit(&q);
QueuePush(&q, 1);
QueuePush(&q, 2);
QueuePush(&q, 3);
QueuePush(&q, 4);
printf("%d ", QueueBack(&q));
QueuePop(&q);
printf("%d ", QueueFront(&q));
QueuePop(&q);
printf("%d ", QueueFront(&q));
QueuePush(&q, 3);
QueuePush(&q, 4);
QueuePush(&q, 5);
printf("QueueSize:%d\\n", QueueSize(&q));
while (!QueueEmpty(&q))
{
printf("%d ", QueueFront(&q));
QueuePop(&q);
}
printf("\\n");
QueueDestroy(&q);
}
int main()
{
TestQueue();
return 0;
}
以上是关于(C语言)手撕数据结构之——队列的主要内容,如果未能解决你的问题,请参考以下文章
手撕C语言标准库qsort(自我实现简化高效版C风格泛型快排)
手把手写C++服务器(35):手撕代码——高并发高QPS技术基石之非阻塞send万字长文