C语言数据结构——队列
·
目录
一、队列概述
1、队列的基本概念
队列是一种基**先进先出(FIFO)**的数据结构,是一种只能在一端进行插入,在另一端进行删除操作的特殊线性表,它按照先进先出的原则存储数据,先进入的数据,在读取数据时先读被读出来。

2、队列的应用
- 举例1:排队系统的实现
- 举例2:使用循环队列存储网络摄像头的数据帧(图像数据)
3、队列的具体实现
- 顺序队列
- 链队列
二、顺序队列
在实现顺序队列之前,我们先来看一看对于顺序队列的操作:
顺序队列可以使用一维数组实现,在顺序队列中有两个指针,一个指针front指向队列的队首(数组的第0个元素),一个指针rear指向队列的队尾(最后一个放入队列的元素)。
1、顺序队列的描述
#define FALSE -1
#define TRUE 0
#define QUEUE_INIT_LEN 100
#define QUEUEINCREMENT 10
typedef int ElemType;
typedef unsigned int uint;
typedef struct SqQueue {
ElemType* base;//存储堆上元素的地址空间的首地址
uint front;//队首指针
uint rear;//队尾指针
}SqQueue;
2、关于顺序队列操作的思考
- 如果对顺序队列进行出队操作,队首指针该如何移动?
- 队首指针往后移动
- 对顺序队列进行出队操作后,被出队的元素所占用的空间怎处理?
- 只能暂时空着,等待下次循环使用

- 如何判断顺序队列是否为满,是否为空呢?
- 判断队列为满和空的依据都是front == rear,因此会有冲突
- 如何判断队列是否溢出呢?
- 当front为0,rear等于队列最大长度时为真溢出

当front不为0,rear等于队列最大长度时为假溢出

3、循环队列的概念
队列上的各个元素逻辑上形成一个圆环状。

如何判断队列是否为满呢?
- 将队列上的一个位置作为空闲位置
- 假设队列的长度为M,当 (rear + 1)% M == font时,认为队列为满

4、循环顺序队列的初始化
/*
* @brief 初始化一个顺序队列
* @param len 顺序队列的初始化长度(可以存储的元素的最大个数)
* @return 返回初始化的顺序队列 * */
SqQueue SqQueue_init(uint size) {
SqQueue s ;
s.base =(ElemType*)malloc(sizeof(ElemType) * size);
s.front = 0;
s.rear = 0;
return s;
}
5、获取顺序队列的长度(实际存储的元素的个数)
/*
* @brief 获取顺序队列的长度
* @param s 顺序队列
* @return 顺序队列的长度
* */
int SqQueue_length(SqQueue s,uint size) {
return (s.rear - s.front+size)%size;
}
6、判断顺序队列是否为空
/*
* @brief 判断顺序队列是否为空
* @param 顺序队列
* @return 为空返回TRUE,不为空返回FALSE
* */
int is_empty(SqQueue s) {
if (s.front==s.rear)
{
return TRUE;
}
else
{
return FALSE;
}
}
7、判断顺序队列是否为满
/*
* @brief 判断顺序队列是否为满
* @param 顺序队列
* @return 为满返回TRUE,不为满返回FALSE
* */
int is_full(SqQueue s) {
if ((s.rear+1)% QUEUE_INIT_LEN==s.front)
{
return TRUE;
}
else
{
return FALSE;
}
}
8、入队
/*
* @brief 循环顺序队列入队
* @param data 需要入队得元素
* @return 成功返回TRUE, 失败返回FALSE
* */
int EnQueue(SqQueue *s,ElemType data) {
if (s==NULL)
{
printf("[%s %d] s is NULL"__FUNCTION__,__LINE__);
return FALSE;
}
if (is_full(*s) == TRUE)
{
//判断队列是否已满
printf("The queue is full");
return FALSE;
}
s->base[s->rear] = data;
s->rear = (s->rear + 1) % QUEUE_INIT_LEN;
return TRUE;
}
9、顺序队列打印
/*
* @brief 输出顺序队列中的元素
*@param s 需要输出顺序队列
* @return 成功返回TRUE,失败返回FALSE
* */
int printf_SqQueue(SqQueue s) {
if (is_empty(s)==TRUE)
{
printf("[%s %d] s is NULL"__FUNCTION__, __LINE__);
return FALSE;
}
int t=s.front;
while (t != s.rear) {
printf("%d ",s.base[t]);
t = (t + 1) % QUEUE_INIT_LEN;
}
printf("\n");
return TRUE;
}
10、出队
/*
* @brief 循环顺序队列出队
* @param data 存储出队元素的指针
* @return 成功返回TRUE, 失败返回FALSE
* */
int DeQueue(SqQueue* s, ElemType* data) {
if (s == NULL)
{
printf("[%s %d] s is NULL"__FUNCTION__, __LINE__);
return FALSE;
}
if (is_empty(*s) == TRUE)
{
//判断队列是否为空
printf("The queue is full");
return FALSE;
}
*data = s->base[s->front];
s->front=(s->front+1)% QUEUE_INIT_LEN;
return TRUE;
}
11、代码展示
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<time.h>
#define FALSE -1
#define TRUE 0
#define QUEUE_INIT_LEN 100
#define QUEUEINCREMENT 10
typedef int ElemType;
typedef unsigned int uint;
typedef struct SqQueue {
ElemType* base;//存储堆上元素的地址空间的首地址
uint front;//队首指针
uint rear;//队尾指针
}SqQueue;
/*
* @brief 初始化一个顺序队列
* @param len 顺序队列的初始化长度(可以存储的元素的最大个数)
* @return 返回初始化的顺序队列 * */
SqQueue SqQueue_init(uint size) {
SqQueue s ;
s.base =(ElemType*)malloc(sizeof(ElemType) * size);
s.front = 0;
s.rear = 0;
return s;
}
/*
* @brief 获取顺序队列的长度
* @param s 顺序队列
* @return 顺序队列的长度
* */
int SqQueue_length(SqQueue s,uint size) {
return (s.rear - s.front+size)%size;
}
/*
* @brief 判断顺序队列是否为空
* @param 顺序队列
* @return 为空返回TRUE,不为空返回FALSE
* */
int is_empty(SqQueue s) {
if (s.front==s.rear)
{
return TRUE;
}
else
{
return FALSE;
}
}
/*
* @brief 判断顺序队列是否为满
* @param 顺序队列
* @return 为满返回TRUE,不为满返回FALSE
* */
int is_full(SqQueue s) {
if ((s.rear+1)% QUEUE_INIT_LEN==s.front)
{
return TRUE;
}
else
{
return FALSE;
}
}
/*
* @brief 循环顺序队列入队
* @param data 需要入队得元素
* @return 成功返回TRUE, 失败返回FALSE
* */
int EnQueue(SqQueue *s,ElemType data) {
if (s==NULL)
{
printf("[%s %d] s is NULL"__FUNCTION__,__LINE__);
return FALSE;
}
if (is_full(*s) == TRUE)
{
//判断队列是否已满
printf("The queue is full");
return FALSE;
}
s->base[s->rear] = data;
s->rear = (s->rear + 1) % QUEUE_INIT_LEN;
return TRUE;
}
/*
* @brief 输出顺序队列中的元素
*@param s 需要输出顺序队列
* @return 成功返回TRUE,失败返回FALSE
* */
int printf_SqQueue(SqQueue s) {
if (is_empty(s)==TRUE)
{
printf("[%s %d] s is NULL"__FUNCTION__, __LINE__);
return FALSE;
}
int t=s.front;
while (t != s.rear) {
printf("%d ",s.base[t]);
t = (t + 1) % QUEUE_INIT_LEN;
}
printf("\n");
return TRUE;
}
/*
* @brief 循环顺序队列出队
* @param data 存储出队元素的指针
* @return 成功返回TRUE, 失败返回FALSE
* */
int DeQueue(SqQueue* s, ElemType* data) {
if (s == NULL)
{
printf("[%s %d] s is NULL"__FUNCTION__, __LINE__);
return FALSE;
}
if (is_empty(*s) == TRUE)
{
//判断队列是否为空
printf("The queue is full");
return FALSE;
}
*data = s->base[s->front];
s->front=(s->front+1)% QUEUE_INIT_LEN;
return TRUE;
}
int main() {
SqQueue s;
s = SqQueue_init(QUEUE_INIT_LEN);
srand(time(NULL));
for (int i = 0; i < 20; i++)
{
int data = rand() % 100;
EnQueue(&s, data);
}
printf("输出队列");
printf_SqQueue(s);
printf("出队");
while (is_empty(s)!=TRUE) {
int data = 0;
DeQueue(&s,&data);
printf("%d ",data);
}
if (is_empty(s)==TRUE)
{
printf("empty");
}
return 0;
}
三、链式队列
链式队列可以理解为对单向链表的操作,入队就是单向链表的尾插法,出队则需要销毁第一个数据结点(类似删除链表上的第一个数据结点)。
代码展示
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<time.h>
#define FALSE -1
#define TRUE 0
#define QUEUE_INIT_LEN 100
#define QUEUEINCREMENT 10
typedef int ElemType;
typedef unsigned int uint;
//定义一个结构体存储指向链表的指针
typedef struct LNode {
ElemType data;
struct LNode* next;
}LNode,*LinkNode;
//定义链表上的一个结点
typedef struct Queue {
LNode* front; //队首指针
LNode* rear; //队尾指针
}Queue,*LinkQueue;
/*
* @brief 初始化一个链式队列
* @return 代表链式队列的结构体
* */
LinkQueue queue_init() {
LinkQueue q=(LinkQueue)malloc(sizeof(Queue));;
q->front = NULL;
q->rear = NULL;
return q;
}
/*
* @brief 入队
* @param L 链式队列的指针
* @param data 需要插入的元素
* @return 成功返回TRUE,失败返回FALSE
* */
int EnQueue(LinkQueue L, ElemType data) {
if (NULL == L) {
printf("[%s %d] L pointer is NULL ...\n", __FUNCTION__, __LINE__);
return FALSE;
}
LNode* tmp = (LNode*)malloc(sizeof(LNode));
tmp->data = data;
tmp->next = NULL;
if (L->front==NULL||L->front->next==NULL)
{
L->front = tmp;
L->rear = tmp;
}
L->rear->next = tmp;
L->rear = tmp;
return TRUE;
}
/*
* @brief 打印链式队列中的元素
* @param L 链式队列结构体
* @return
* */
int queue_printf(LinkQueue que) {
if (NULL == que||NULL==que->front) {
printf("[%s %d] L pointer is NULL ...\n", __FUNCTION__, __LINE__);
return FALSE;
}
LNode* tmp=que->front;
while (tmp!=NULL) {
printf("%d ", tmp->data);
tmp = tmp->next;
}
printf("\n");
return TRUE;
}
/*
* @brief 出队
* @param L 链式队列的指针
* @param data 需要出队的元素
* @return 成功返回TRUE,失败返回FALSE
* */
int DeQueue(LinkQueue que, ElemType* data) {
if (NULL == que || NULL == que->front) {
printf("[%s %d] L pointer is NULL ...\n", __FUNCTION__, __LINE__);
return FALSE;
}
LNode* tmp = que->front;
*data = tmp->data;
tmp = tmp->next;
free(que);
que->front = tmp;
return TRUE;
}
int main() {
srand(time(NULL));
LinkQueue que;
que= queue_init();
for (int i = 0; i < 10; i++)
{
int data = rand() % 100;
EnQueue(que, data);
}
queue_printf(que);
int data;
DeQueue(que, &data);
queue_printf(que);
printf("%d ", data);
}
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)