目录
一、队列的概念和结构
二、队列的实现
头文件
初始化
入队列和出队列
获取队头队尾元素
队列有效数据数及队列判空
队列的销毁
完整源码
dl.h
dl.c
一、队列的概念和结构
队列是一种只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出,进行插入操作的一端称为队尾,进行删除操作的一端称为队头,与栈刚好相反,栈时先进后出,队列是先进先出。
二、队列的实现
队列和栈类似,都可以用链表和数组实现,不过有一点不同的是,队列用链表实现会更好一点,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低,这篇文章就用链表实现。
头文件
写入整个程序需要用到的头文件以及队列各个功能的函数名
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
// 链式结构:表示队列
typedef struct QListNode
{
struct QListNode* _pNext;
QDataType _data;
}QNode;
// 队列的结构
typedef struct Queue
{
QNode* _front;
QNode* _rear;
}Queue;
// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDataType data);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDataType QueueFront(Queue* q);
// 获取队列队尾元素
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);
因为是基于链表实现所以这里需要写连个结构体,一个是队列各个节点的数据,另一个是能让队列中通过单个节点能够找到其余节点,第二个结构体用到了第一个结构体逻辑上也相当于将第一个结构体包含在内了。
初始化
前后指针都置空,队列中元素数归0
void QueueInit(Queue* q)
{
q->front = NULL;
q->rear = NULL;
q->size = 0;
}
入队列和出队列
入队列在队尾,出队列在队头
void QueuePush(Queue* q, QDataType data)
{
QNode* new = (QNode*)malloc(sizeof(QNode));
new->next = NULL;
new->data = data;
if (q->front == NULL)
{
q->front = q->rear = new;
}
else
{
q->rear->next = new;
q->rear = q->rear->next;
}
q->size++;
}
申请空间,输入数据,如果为首个数据,就要充当队头和队尾两个角色 ,如果不是,只要修改队尾就行了,接在旧的队尾上成为新的队尾,最后队列数据元素数+1。
void QueuePop(Queue* q)
{
assert(q->front);
QNode* a = q->front->next;
free(q->front);
q->front = a;
q->size--;
}
删除队头,让第二个数据担任新的队头,队列数据元素数-1。
获取队头队尾元素
这个就很简单,直接取数据就行了
QDataType QueueFront(Queue* q)//取队头
{
assert(q->front);
return q->front->data;
}
QDataType QueueBack(Queue* q)//取队尾
{
assert(q->rear);
return q->rear->data;
}
队列有效数据数及队列判空
取队列有效数据和取队头队尾元素一样,直接取数据就行了。
int QueueSize(Queue* q)
{
assert(q->front);
assert(q->size > 0);
return q->size;
}
队列的判空直接看有效数据是否为0就可以判断出
bool QueueEmpty(Queue* q)
{
assert(q);
return q->size == 0;
}
队列的销毁
先把每个节点都销毁,再把队头指针和队尾指针置空,队列数据数归0
void QueueDestroy(Queue* q)
{
while (q->front)
{
QNode* a = q->front->next;
free(q->front);
q->front = a;
}
q->front = NULL;
q->rear = NULL;
q->size = 0;
}
完整源码
dl.h
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int QDataType;
typedef struct QListNode
{
struct QListNode* next;
QDataType data;
}QNode;
typedef struct Queue
{
QNode* front;
QNode* rear;
int size;
}Queue;
void QueueInit(Queue* q);
void QueuePush(Queue* q, QDataType data);
void QueuePop(Queue* q);
QDataType QueueFront(Queue* q);
QDataType QueueBack(Queue* q);
int QueueSize(Queue* q);
bool QueueEmpty(Queue* q);
void QueueDestroy(Queue* q);
dl.c
#include"dl.h"
void QueueInit(Queue* q)
{
q->front = NULL;
q->rear = NULL;
q->size = 0;
}
void QueuePush(Queue* q, QDataType data)
{
QNode* new = (QNode*)malloc(sizeof(QNode));
new->next = NULL;
new->data = data;
if (q->front == NULL)
{
q->front = q->rear = new;
}
else
{
q->rear->next = new;
q->rear = q->rear->next;
}
q->size++;
}
void QueuePop(Queue* q)
{
assert(q->front);
QNode* a = q->front->next;
free(q->front);
q->front = a;
q->size--;
}
QDataType QueueFront(Queue* q)
{
assert(q->front);
return q->front->data;
}
QDataType QueueBack(Queue* q)
{
assert(q->rear);
return q->rear->data;
}
int QueueSize(Queue* q)
{
assert(q->front);
assert(q->size > 0);
return q->size;
}
bool QueueEmpty(Queue* q)
{
assert(q);
return q->size == 0;
}
void QueueDestroy(Queue* q)
{
while (q->front)
{
QNode* a = q->front->next;
free(q->front);
q->front = a;
}
q->front = NULL;
q->rear = NULL;
q->size = 0;
}
代码还是要自己一个一个的敲出来,这样才能加深对队列知识的理解。
另外了解一下,实际中我们有时还会使用一种队列叫循环队列,生产者消费者模型时可以就会使用循环队列,环形队列可以使用数组实现,也可以使用循环链表实现。
本篇的内容就到这里了,希望对各位有帮助,如果有错误欢迎指出。