C语言数据结构——队列

目录

一、队列概述

1、队列的基本概念

2、队列的具体实现

二、顺序队列

1、关于顺序队列操作的思考

2、循环队列的概念

3、代码实现一个顺序队列

1、顺序队列结构体的描述

2、循环顺序队列的初始化 

3、获取顺序队列的长度(实际存储的元素的个数)

4、判断顺序队列是否为空 

5、判断顺序队列是否为满 

6、入队

7、顺序队列打印的元素

8、出队

9、完整代码

三、链式队列

1、链式队列结构体的描述

2、链式队列的初始化

3、入队

4、打印链式队列的元素

5、出队 

6、完整代码 


嗨,感谢你打开这篇文章!👋 如果阅读中发现任何笔误或表述不清的地方,欢迎随时留言告诉我~你的视角会让内容变得更完善!

一、队列概述

1、队列的基本概念

队列是一种基于先进先出(FIFO)的数据结构,是一种只能在一端进行插入,在另一端进行删除操作的特殊线性表,它按照先进先出的原则存储数据,先进入的数据,在读取数据时先读被读出来。

2、队列的具体实现

  • 顺序队列

  • 链式队队

二、顺序队列

在实现顺序队列之前,我们先来看一看对于顺序队列的操作:

 顺序队列可以使用一维数组实现,在顺序队列中有两个指针,一个指针front指向队列的队首(数组的首个元素),一个指针rear指向队列的队尾(最后一个放入队列的元素的后一个空间)。 

1、关于顺序队列操作的思考

1.如果对顺序队列进行出队操作,队首指针该如何移动?

答:队首指针往后移动

2.对顺序队列进行出队操作后,被出队的元素所占用的空间怎处理?

答:只能暂时空着,等待下次循环使用

 3.如何判断顺序队列是否为满,是否为空呢?

答:判断队列为满和空的依据都是front == rear,因此会有冲突

4.如何判断队列是否溢出呢?

答:(1)当front为0,rear等于队列最大长度时为真溢出

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

 解决方案:使用循环队列。

2、循环队列的概念

队列上的各个元素逻辑上形成一个圆环状

1.如何判断队列是否为满呢?

答:(1)将队列上的一个位置作为空闲位置

       (2) 假设队列的长度为M,当 (rear + 1)% M == font时,认为队列为满

3、代码实现一个顺序队列

1、顺序队列结构体的描述

#define TRUE 1
#define FALSE 0

typedef int Elemtype;
typedef unsigned int uint;

#define QUEUE_INIT_LEN 10 //初始化长度
//顺序队列结构体的描述
typedef struct sqQueue
{
	Elemtype* base; //存储堆上元素的地址空间的首地址 
	uint front; //队首指针 下标索引 用下标当成指针
	uint rear; //队尾指针 
}sqQueue;

2、循环顺序队列的初始化 

/* 
 *@brief 初始化一个顺序队列 
 * @param len 顺序队列的初始化长度(可以存储的元素的最大个数) 
 * @return 返回初始化的顺序队列 
 * */
sqQueue sqQuene_init(uint len)
{
	sqQueue s;
	s.base = (Elemtype*)malloc(len * sizeof(Elemtype));
	s.front = 0; 
	s.rear = 0; 
	
	return s;
}

3、获取顺序队列的长度(实际存储的元素的个数)

/* 
 * @brief 获取顺序队列的长度 
 * @param s 顺序队列 
 * @return 顺序队列的长度 
 * */
int SqQueue_length(sqQueue s) 
{ 
	return s.rear - s.front; 
}

4、判断顺序队列是否为空 

/* 
 * @brief 判断顺序队列是否为空 
 * @param 顺序队列 
 * @return 为空返回TRUE,不为空返回FALSE 
 * */
int is_empty(sqQueue s) 
{ 
	if (s.front == s.rear)
	{
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

5、判断顺序队列是否为满 

/* 
 * @brief 判断顺序队列是否为满 
 * @param 顺序队列 
 * @return 为满返回TRUE,不为满返回FALSE 
 * */ 
int is_full(sqQueue s)
{
	if ((s.rear + 1) % QUEUE_INIT_LEN == 0)
		return TRUE;
	else
		return FALSE;
}

6、入队

/* 
 * @brief 循环顺序队列入队 
 * @param data 需要入队得元素
 * @return 成功返回TRUE, 失败返回FALSE 
 * */ 
int EnQueue(sqQueue* s, Elemtype data)
{
	if (NULL == s )
	{
		return FALSE;
	}
	if (is_full(*s) == TRUE)
	{
		printf("[%s %d] queue is empty ...\n", __FUNCTION__, __LINE__);
		return FALSE;
	}

	//将需要入队的元素保存在队尾指针rear所指向的空间中
	s->base[s->rear] = data;
	//队尾指针rear往后移一个位置
	s->rear = (s->rear + 1) % QUEUE_INIT_LEN;

	return TRUE;
}

7、顺序队列打印的元素

/*
 * @brief 打印顺序队列中的元素
 * @param s 顺序队列结构体
 * @return
 * */
int printf_sqQueue(sqQueue s)
{
	if (is_empty(s) == TRUE)
	{
		printf("[%s %d] queue is empty ...\n", __FUNCTION__, __LINE__);
		return FALSE;
	}

	int i = s.front;
	printf("printf sqQueue:");
	while (i != s.rear)
	{
		printf(" %d", s.base[i]);
		i = (i + 1) % QUEUE_INIT_LEN;
	}
	printf("\n");
	return TRUE;
}

8、出队

/*
 * @brief 循环顺序队列出队
 * @param data 存储出队元素的指针 
 * @return 成功返回TRUE, 失败返回FALSE
 * */
int DeQueue(sqQueue* s, Elemtype* data)
{
	if (NULL == s || NULL == data)
	{
		return FALSE;
	}
	if (is_empty(*s) == TRUE) 
	{ 
		printf("[%s %d] queue is empty ...\n", __FUNCTION__, __LINE__);
		return FALSE; 
	}

	//取出队首元素:将队首元素存储到的data指针所指向的空间
	*data = s->base[s->front];
	//队首指针往后移动一个位置
	s->front = (s->front + 1) % QUEUE_INIT_LEN;

	return TRUE;
}

9、完整代码

#include<stdio.h>
#include<stdlib.h>

#define TRUE 1
#define FALSE 0

typedef int Elemtype;
typedef unsigned int uint;

#define QUEUE_INIT_LEN 10 //初始化长度
//顺序队列结构体的描述
typedef struct sqQueue
{
	Elemtype* base; //存储堆上元素的地址空间的首地址 
	uint front; //队首指针 下标索引 用下标当成指针
	uint rear; //队尾指针 
}sqQueue;

/* 
 *@brief 初始化一个顺序队列 
 * @param len 顺序队列的初始化长度(可以存储的元素的最大个数) 
 * @return 返回初始化的顺序队列 
 * */
sqQueue sqQuene_init(uint len)
{
	sqQueue s;
	s.base = (Elemtype*)malloc(len * sizeof(Elemtype));
	s.front = 0; 
	s.rear = 0; 
	
	return s;
}

/* 
 * @brief 获取顺序队列的长度 
 * @param s 顺序队列 
 * @return 顺序队列的长度 
 * */
int SqQueue_length(sqQueue s) 
{ 
	return s.rear - s.front; 
}
/* 
 * @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 == 0)
		return TRUE;
	else
		return FALSE;
}

//打印队列数据
int printf_sqQueue(sqQueue s)
{
	if (is_empty(s) == TRUE)
	{
		printf("[%s %d] queue is empty ...\n", __FUNCTION__, __LINE__);
		return FALSE;
	}

	int i = s.front;
	printf("printf sqQueue:");
	while (i != s.rear)
	{
		printf(" %d", s.base[i]);
		i = (i + 1) % QUEUE_INIT_LEN;
	}
	printf("\n");
	return TRUE;
}
/* 
 * @brief 循环顺序队列入队 
 * @param data 需要入队得元素
 * @return 成功返回TRUE, 失败返回FALSE 
 * */ 
int EnQueue(sqQueue* s, Elemtype data)
{
	if (NULL == s )
	{
		return FALSE;
	}
	if (is_full(*s) == TRUE)
	{
		printf("[%s %d] queue is empty ...\n", __FUNCTION__, __LINE__);
		return FALSE;
	}

	//将需要入队的元素保存在队尾指针rear所指向的空间中
	s->base[s->rear] = data;
	//队尾指针rear往后移一个位置
	s->rear = (s->rear + 1) % QUEUE_INIT_LEN;

	return TRUE;
}

/*
 * @brief 循环顺序队列出队
 * @param data 存储出队元素的指针 
 * @return 成功返回TRUE, 失败返回FALSE
 * */
int DeQueue(sqQueue* s, Elemtype* data)
{
	if (NULL == s || NULL == data)
	{
		return FALSE;
	}
	if (is_empty(*s) == TRUE) 
	{ 
		printf("[%s %d] queue is empty ...\n", __FUNCTION__, __LINE__);
		return FALSE; 
	}

	//取出队首元素:将队首元素存储到的data指针所指向的空间
	*data = s->base[s->front];
	//队首指针往后移动一个位置
	s->front = (s->front + 1) % QUEUE_INIT_LEN;

	return TRUE;
}
int main()
{
	sqQueue s;
	s = sqQuene_init(QUEUE_INIT_LEN);

	int i = 0;
	for (i = 0; i < 9; i++)
	{
		EnQueue(&s, i);
	}
	printf_sqQueue(s);

	printf("printf DeQueue:");
	while (is_empty(s) != TRUE)
	{
		Elemtype data;
		DeQueue(&s, &data);
		printf(" %d", data);
	}
	printf("\n");

	return 0;
}

三、链式队列

链式队列可以理解为对单向链表的操作,入队就是单向链表的尾插法,出队则需要销毁第一个数据结点(类似删除链表上的第一个数据结点)。 

1、链式队列结构体的描述

#define TRUE 1
#define FALSE 0

typedef int Elemtype;
typedef unsigned int uint;
/* 
 * 链式队列可以理解成一个通过尾插法创建的链表(可以带头结点也可以不带头结点) 
 * */
//定义一个结构体描述的链表的结点
typedef struct lnode
{
	Elemtype data;
	struct lnode* next; //指向当前结点的下一个结点的指针(保存了下一个结点的存储位置)
}lnode;
//定义一个结构体描述的链表队列
typedef struct Linkqueue
{
	lnode* front;//链表队列首指针
	lnode* rear; //链表队列尾指针
}Linkqueue;

2、链式队列的初始化

* 
 * @brief 初始化一个链式队列 
 * @return 代表链式队列的结构体 
 * */
Linkqueue queue_init()
{
	//创建一个链式队列
	Linkqueue s;
	s.front = NULL;
	s.rear = NULL;

	return s;
}

3、入队

/* 
 * @brief 入队 
 * @param s 链式队列的指针 
 * @param data 需要插入的元素 
 * @return 成功返回TRUE,失败返回FALSE 
 * */
int EnQueue(Linkqueue* s, Elemtype data)
{
	if (NULL == s) 
		return FALSE;
	//创建一个结点
	lnode* p = (lnode*)malloc(sizeof(lnode));
	if (NULL == p)
	{
		return FALSE;
	}
	p->data = data;
	p->next = NULL;
	//先判断队列是否为空队列
	if (NULL == s->front)
	{
		s->front = p;
		s->rear = p;
		return TRUE;
	}
	//如果队列不为空,那么将rear指向新的结点
	s->rear->next = p;
	s->rear = p;

	return TRUE;
}

4、打印链式队列的元素

/* 
 * @brief 打印链式队列中的元素 
 * @param s 链式队列结构体 
 * @return 
 * */ 
void print_queue(Linkqueue s)
{
	lnode* temp;
	temp = s.front;
	printf("printf queue:");
	while (temp != NULL)
	{
		printf(" %d", temp->data);
		temp = temp->next;//让tmp指针指向下一个结点
	}
	printf("\n");
}

5、出队 

/*
 * @brief 出队
 * @param s 链式队列的指针
 * @param data 需要得到的元素的地址
 * @return 成功返回TRUE,失败返回FALSE
 * */
int DeQueue(Linkqueue* s, Elemtype* data)
{
	if (NULL == s || NULL == data) 
		return FALSE; 
	if (NULL == s->front) 
		return FALSE;
	//首先保存链式队列上的第一个结点的值
	*data = s->front->data;
	//使用临时指针执行队首 
	lnode *temp = s->front; 
	//队首指针指向后一个结点(出队后原来队列上的第二个结点变成了新的队首结点)
	s->front = s->front->next; 
	//删除原来的队首结点 
	free(temp);
	return TRUE;
}

6、完整代码 

#include<stdio.h>
#include<stdlib.h>

#define TRUE 1
#define FALSE 0

typedef int Elemtype;
typedef unsigned int uint;
/* 
 * 链式队列可以理解成一个通过尾插法创建的链表(可以带头结点也可以不带头结点) 
 * */
//定义一个结构体描述的链表的结点
typedef struct lnode
{
	Elemtype data;
	struct lnode* next; //指向当前结点的下一个结点的指针(保存了下一个结点的存储位置)
}lnode;
//定义一个结构体描述的链表队列
typedef struct Linkqueue
{
	lnode* front;//链表队列首指针
	lnode* rear; //链表队列尾指针
}Linkqueue;

/* 
 * @brief 初始化一个链式队列 
 * @return 代表链式队列的结构体 
 * */
Linkqueue queue_init()
{
	//创建一个链式队列
	Linkqueue s;
	s.front = NULL;
	s.rear = NULL;

	return s;
}

/* 
 * @brief 打印链式队列中的元素 
 * @param s 链式队列结构体 
 * @return 
 * */ 
void print_queue(Linkqueue s)
{
	lnode* temp;
	temp = s.front;
	printf("printf queue:");
	while (temp != NULL)
	{
		printf(" %d", temp->data);
		temp = temp->next;//让tmp指针指向下一个结点
	}
	printf("\n");
}

/* 
 * @brief 入队 
 * @param s 链式队列的指针 
 * @param data 需要插入的元素 
 * @return 成功返回TRUE,失败返回FALSE 
 * */
int EnQueue(Linkqueue* s, Elemtype data)
{
	if (NULL == s) 
		return FALSE;
	//创建一个结点
	lnode* p = (lnode*)malloc(sizeof(lnode));
	if (NULL == p)
	{
		return FALSE;
	}
	p->data = data;
	p->next = NULL;
	//先判断队列是否为空队列
	if (NULL == s->front)
	{
		s->front = p;
		s->rear = p;
		return TRUE;
	}
	//如果队列不为空,那么将rear指向新的结点
	s->rear->next = p;
	s->rear = p;

	return TRUE;
}

/*
 * @brief 出队
 * @param s 链式队列的指针
 * @param data 需要得到的元素的地址
 * @return 成功返回TRUE,失败返回FALSE
 * */
int DeQueue(Linkqueue* s, Elemtype* data)
{
	if (NULL == s || NULL == data) 
		return FALSE; 
	if (NULL == s->front) 
		return FALSE;
	//首先保存链式队列上的第一个结点的值
	*data = s->front->data;
	//使用临时指针执行队首 
	lnode *temp = s->front; 
	//队首指针指向后一个结点(出队后原来队列上的第二个结点变成了新的队首结点)
	s->front = s->front->next; 
	//删除原来的队首结点 
	free(temp);
	return TRUE;
}

int main() 
{
	//创建一个链式队列
	Linkqueue s = queue_init();

	int i = 0;
	for (i = 0; i < 5; i++)
	{
		EnQueue(&s, i);
	}
	print_queue(s); 

   Elemtype data = 0;
   printf("printf dequeue:");
   while (DeQueue(&s, &data) != FALSE)
   {
	   printf(" %d", data);
   }
   printf("\n");
   return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值