当前位置: 首页 > article >正文

4.C_数据结构_队列

概述

什么是队列:

队列是限定在两端进行插入操作和删除操作的线性表。具有先入先出(FIFO)的特点

相关名词:

  • 队尾:写入数据的一段
  • 队头:读取数据的一段
  • 空队:队列中没有数据,队头指针 = 队尾指针
  • 满队:队列中存满了数据,队尾指针 + 1 = 队头指针

循环队列

1、基本内容

循环队列是以数组形式构成的队列数据结构。

循环队列的结构体如下:

typedef int data_t; //队列数据类型
#define N 64        //队列容量
typedef struct{
    data_t data[N]; //数据
    int front;      //队头位置,代表将要出队的位置
    int rear;       //队尾位置,代表将要入队的位置
}sequeue_t;

入队与出队示意图: 

 在循环队列中,fornt代表将要出队的位置,rear代表将要入队的位置。

  • 空队:当fornt = rear时,代表将要出队的地方还没有入队数据,因此整个队列为空。
  • 入队:当想要入队时,只需要向rear的位置填入数据即可入队,入队之后应该rear++,让rear指向下一个入队的位置。
  • 出队:当想要出队时,只需要从fornt的位置获取数据即可出队,出队之后应该fornt++,让fornt指向下一个要出队的位置。
  • 满队:当rear+1 = front时,代表已经满队(这里省略了%限定范围)
  • fornt与rear指向空间问题:在循环队列中,满队时会有一个冗余空间不能使用。

循环队列代码的文件构成:

  • sequeue.h:数据结构的定义、运算函数接口
  • sequeue.c:运算函数接口的实现
  • test.c:使用数据结构实现的应用功能代码

循环队列相关函数: 

  • 创建:sequeue* queue_create(void);
  • 删除:int queue_del(sequeue** pQueue); 
  • 入队列:int enter_queue(sequeue* pQueue,data_t value);
  • 出队列:int out_queue(sequeue* pQueue,data_t* value);

2、功能实现 

2.1 创建

创建循环队列就是申请空间,并让入队位置与出队位置相等,这代表队列为空。

具体代码实现如下:

/*
 * queue_create:创建队列
 * @ret  NULL--err  other--空队列指针
 * */
sequeue* queue_create(void){
	sequeue* pQueue = NULL;
	//1.申请空间
	pQueue = (sequeue*)malloc(sizeof(sequeue));
	if(pQueue == NULL){
		printf("malloc err\n");
		return NULL;
	}
	//2.初始化,front = rear代表空队列
	memset(pQueue->data,0,N*sizeof(data_t));
	pQueue->front = 0;
	pQueue->rear = 0;
	return pQueue;
} 

2.2 删除

删除就是释放申请的空间即可。

具体代码实现如下:

/*
 * queue_del:销毁队列
 * param pQueue:要销毁的队列
 * @ret  -1--err  0--success
 * */
int queue_del(sequeue** pQueue){
	//1.判断参数有效性
	if(*pQueue == NULL){
		printf("pQueue is NULL\n");
		return -1;
	}
	free(*pQueue);
	*pQueue = NULL;
	return 0;
}

2.3 入队列

入队列的示意图如 "1、基本内容" 中所示,只需要在rear处填入数据并把rear进行偏移即可。

注意:入队列时,需要判断队列是否已满

具体代码实现如下:

/*
 * enter_queue:入队列
 * param pQueue:要入哪一个队列
 * param value:要入队的数据
 * @ret  -1--err  0--success
 * */
int enter_queue(sequeue* pQueue,data_t value){
	//1.判断参数有效性
	if(pQueue == NULL){
		printf("pQueue is NULL\n");
		return -1;
	}
	//2.判断队列是否已满
	if( ((pQueue->rear+1)%N) == pQueue->front ){
		printf("queue is full\n");
		return -1;
	}
	//3.入队列,就是在rear出写入数据
	pQueue->data[pQueue->rear] = value;
	pQueue->rear = (pQueue->rear+1)%N;
	return 0;
}

2.4 出队列

出队列的示意图如 "1、基本内容" 中所示,只需要在front处取出数据并把front进行偏移即可。

注意:出队列时,需要判断队列是否为空

具体代码实现如下:

/*
 * out_queue:出队列
 * param pQueue:要出哪一个队列的数据
 * param value:要出队的数据存放的位置
 * @ret  -1--err  0--success
 * */
int out_queue(sequeue* pQueue,data_t* value){
	//1.判断参数有效性
	if(pQueue == NULL){
		printf("pQueue is NULL\n");
		return -1;
	}
	//2.判断队列是否为空
	if(pQueue->front == pQueue->rear){
		printf("queue is empty\n");
		return -1;
	}
	//3.出队列,就是从front处读数据
	*value = pQueue->data[pQueue->front];
	pQueue->front = (pQueue->front+1)%N;
	return 0;
}

链式队列

1、基本内容

链式队列是以链表形式构成的队列数据结构。

链式队列的结构体如下:

typedef int data_t;
//链表
typedef struct node{
    data_t data;
    struct node* pNext;
}listnode,*linklist;
//队列
typedef struct{
    linklist front;//始终指向冗余的头
    linklist reat; //始终指向入队的位置,新数据接在rear后
}linkqueue;

入队与出队示意图: 

在链式队列中,fornt代表冗余的头,rear代表将要入队的位置。

  • 空队:当fornt、rear都指向冗余节点时,代表没有数据,即为空队
  • 入队:当想要入队时,只需要将数据链接到rear的位置之后即可。
  • 出队:当想要出队时,只需要把front后一个数据释放即可,当释放后为空时,需要将rear指向冗余的头。

链式队列代码的文件构成:

  • linkqueue.h:数据结构的定义、运算函数接口
  • linkqueue.c:运算函数接口的实现
  • test.c:使用数据结构实现的应用功能代码

链式队列相关函数: 

  • 创建:linkqueue* queue_create(void);
  • 删除:int queue_delete(linkqueue** pQueue);
  • 入队列:int enter_queue(linkqueue* pQueue,data_t value);
  • 出队列:int out_queue(linkqueue* pQueue,data_t* value)

2、功能实现

2.1 创建

创建链式队列,需要申请两个空间:冗余的头和队列。初始化时需要把front、rear指向冗余的头,代表这个队列为空队。

具体代码实现如下:

/*
 * queue_create:创建一个空队列
 * @ret  NULL--err  other--空队列指针
 * */
linkqueue* queue_create(void){

	linkqueue* pQueue = NULL;
	linklist pLink = NULL;

	//1.申请空间
	//1.1 队列空间
	pQueue = (linkqueue*)malloc(sizeof(linkqueue));
	if(pQueue == NULL){
		printf("pQueue malloc err\n");
		return NULL;
	}
	//1.2 单链表空间
	pLink = (linklist)malloc(sizeof(listnode));
	if(pLink == NULL){
		printf("pLink malloc err\n");
		free(pQueue);//释放前面申请的空间
		return NULL;
	}
	//2.初始化
	pLink->data = 0;
	pLink->pNext = NULL;
	pQueue->front = pLink;
	pQueue->rear = pLink;
	return pQueue;
}

2.2 删除

删除链式队列,首先需要释放单链表的空间,之后再释放队列的空间。

具体代码实现如下:

/*
 * queue_delete:删除整个队列
 * param pQueue:队列地址
 * @ret  -1--err  0--success
 * */
int queue_delete(linkqueue** pQueue){
	linklist pTmp = NULL;
	//1.判断参数有效性
	if(*pQueue == NULL){
		printf("pQueue is NULL\n");
		return -1;
	}
	//2.开始释放链表
	while((*pQueue)->front != NULL){
		pTmp = (*pQueue)->front;
		(*pQueue)->front = (*pQueue)->front->pNext;
		free(pTmp);
	}
	//3.释放队列
	free(*pQueue);
	*pQueue = NULL;
	return 0;
}

2.3 入队列

入队列的示意图如 "1、基本内容" 中所示,只需要将新数据链接到rear后即可,之后rear需要指向新数据。

具体代码实现如下:

/*
 * enter_queue:入队列
 * param pQueue:队列地址
 * param value:入队数据
 * @ret  -1--err  0--success
 * */
int enter_queue(linkqueue* pQueue,data_t value){
	linklist pLink = NULL;
	//1.判断参数有效性
	if(pQueue == NULL){
		printf("pQueue is NULL\n");
		return -1;
	}
	//2.创建链表结点
	pLink = (linklist)malloc(sizeof(listnode));
	if(pLink == NULL){
		printf("malloc err\n");
		return -1;
	}
	pLink->data = value;
	pLink->pNext = NULL;
	//3.入队列
	//rear后链接新结点
	pQueue->rear->pNext = pLink;
	//队列指针偏移
	pQueue->rear = pLink;
	return 0;
}

2.4 出队列

出队列的示意图如 "1、基本内容" 中所示,需要将front后一个数据进行释放,并连接上剩余的数据。

注意点1:当出队列后,队列为空队,这时需要将rear指向冗余的头

注意点2:出队列之前需要先判断队列是否为空

注意点3:出队之后,需要释放出队元素的空间

具体的代码实现如下:

/*
 * out_queue:出队列
 * param pQueue:队列地址
 * param value:出队数据存放的地址
 * @ret  -1--err  0--success
 * */
int out_queue(linkqueue* pQueue,data_t* value){
	linklist pTmp = NULL;
	//1.判断参数有效性
	if(pQueue == NULL){
		printf("pQueue is NULL\n");
		return -1;
	}
	//2.判断是否为空队列
	if(pQueue->front == pQueue->rear){
		printf("queue is empty\n");
		return -1;
	}
	//3.保存剩余数据
	pTmp = pQueue->front->pNext->pNext;
	//4.出队后队列为空时,需将rear指向冗余头部代表空队列
	if(pQueue->front->pNext == pQueue->rear){
		pQueue->rear = pQueue->front;
	}
	//5.开始出队列
	*value = pQueue->front->pNext->data;
	free(pQueue->front->pNext);
	pQueue->front->pNext = pTmp;
	return 0;
}


http://www.kler.cn/news/306251.html

相关文章:

  • Java异常处理详细讲解及常见面试问题
  • 无人机巡检:突破传统局限,引领智能监测新时代
  • java 网络编程URL与URLConnection的使用
  • 深入解析 Apache Ranger
  • 电容的不同材质对应的温度范围
  • Redis主要问题(缓存问题)
  • pyflink 安装和测试
  • Matlab simulink建模与仿真 第十四章(信号输出库)
  • 计算机毕业设计 智慧物业服务系统的设计与实现 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试
  • Elasticsearch 聚合搜索
  • 网络安全 L2 Introduction to Cryptography 密码学
  • 学习整理vue前端框架项目目录结构的含义
  • Rust 所有权 Slices
  • 64. 求 1+2+…+n
  • Python快速入门 —— 第二节:函数与控制语句
  • 【C++】c++的继承
  • 面试常见题之spring
  • JAVA实现压缩包解压兼容Windows系统和MacOs
  • 【机器学习】期望最大化算法的基本概念以及再高斯混合模型的应用
  • Go语言错误处理详解
  • Cubieboard2(一) 官方镜像使用与配置
  • 【LLM多模态】文生视频评测基准VBench
  • llama3论文阅读
  • 火箭动力原理精解【1】
  • 学习大数据DAY57 新的接口配置
  • AI学习指南深度学习篇-RMSprop的数学原理
  • Python 课程11-Web 开发
  • Android 10.0 mtk平板camera2横屏预览旋转90度横屏保存圆形预览缩略图旋转90度功能实现
  • 蓝桥杯3. 压缩字符串
  • 掌握远程管理的艺术:揭秘Python的pywinrm库