IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【数据结构与算法】程序内功篇五--队列 -> 正文阅读

[数据结构与算法]【数据结构与算法】程序内功篇五--队列


一、队列

1、队列原理

队列是限制在两端进行插入操作删除操作线性表

允许进行存入操作的一端称为“队尾

允许进行删除操作的一端称为“队头

当线性表中没有元素时,称为“空队

特点 :先进先出FIFO


2、队列演示

在这里插入图片描述


二、顺序队列

>1、顺序队列原理

规定:

front指向队头元素的位置; rear指向队尾元素的下一个位置。

在队列操作过程中,为了提高效率,以调整指针代替队列元素的移动,并将数组作为循环队列的操作空间。
为区别空队满队,满队元素个数比数组元素个数少一个。
在这里插入图片描述

因此顺序队列结构体定义为:

#define DEBUG 1   //1-打开debug,0关闭debug
typedef  int  data_t ;    /*定义队列中数据元素的数据类型*/
#define  N  64	    /*定义队列的容量*/
typedef  struct {
      data_t  data[N] ;   /*用数组作为队列的储存空间*/
      int  front, rear ;     /*指示队头位置和队尾位置的指针*/
} s_queue,*squeue ; 	     /*顺序队列类型定义*/

>2、顺序队列的创建

/**
 * @description: 顺序队列的创建
 * @param {*}
 * @return {squeue-队列指针}
 */
squeue squeue_create()
{
	squeue queue = (squeue)malloc(sizeof(s_queue));
	if(queue == NULL)
	{
		#if DEBUG
		printf("squeue create error!\n");
		#endif
		return 0;
	}
	
	memset(queue->data,0,sizeof(queue->data));  
	queue->front = queue->rear =0;

	return queue;
}

>3、顺序队列的入队

/**
 * @description: 入顺序队列
 * @param {squeue} queue-队列指针
 * @param {data_t} value-入队列的值
 * @return {0-函数失败,1-函数成功}
 */
int squeue_enter(squeue queue, data_t value)
{
	if(queue == NULL)
	{
		#if DEBUG
		printf("squeue create error!\n");
		#endif
		return 0;
	}

	if((queue->rear+1)%N == queue->front)
	{
		#if DEBUG
		printf("squeue already full!\n");
		#endif
		return 0;
	}
	queue->data[queue->rear] = value;
	queue->rear = (queue->rear+1)%N;  //取余可以是值满后回到0

	return 1;
}

>4、顺序队列的出队

/**
 * @description:出队列 
 * @param {squeue} queue-队列指针
 * @return {0-函数失败,value-出队列单元储存的值}
 */
int squeue_out(squeue queue)
{	
	data_t value;
	if(queue == NULL)
	{
		#if DEBUG
		printf("squeue create error!\n");
		#endif
		return 0;
	}

	if(queue->front == queue->rear)
	{
		#if DEBUG
		printf("squeue is empty!\n");
		#endif
		return 0;
	}
	
	value = queue->data[queue->front];
	queue->data[queue->front] = 0;
	queue->front = (queue->front+1)%N;

	return value;
}

>5、顺序队列的释放

/**
 * @description: 队列释放
 * @param {squeue} queue-队列指针
 * @return {0-函数失败,1-函数成功}
 */
int squeue_free(squeue queue)
{
	if(queue == NULL)
	{
		#if DEBUG
		printf("squeue create error!\n");
		#endif
		return 0;
	}

	free(queue);

	return 1;
}

>6、顺序队列的清空

/**
 * @description: 队列清空
 * @param {squeue} queue-队列指针
 * @return {0-函数失败,1-函数成功}
 */
int squeue_clear(squeue queue)
{
	if(queue == NULL)
	{
		#if DEBUG
		printf("squeue create error!\n");
		#endif
		return 0;
	}

	memset(queue->data,0,sizeof(queue->data));
	queue->front = queue->rear = 0;

	return 1;
}

>7、队列是否为空的判断

/**
 * @description: 判断队列是否为空
 * @param {squeue} queue-队列指针
 * @return {-1-函数失败,1-队列为空,0-队列不为空}
 */
int squeue_empty(squeue queue)
{
	if(queue == NULL)
	{
		#if DEBUG
		printf("squeue create error!\n");
		#endif
		return -1;
	}

	return queue->front == queue->rear? 1:0;
}

>8、队列是否为满的判断

/**
 * @description: 判断队列是否满
 * @param {squeue} queue
 * @return {-1-函数失败,1-队列满,0-队列不满}
 */
int squeue_full(squeue queue)
{
	if(queue == NULL)
	{
		#if DEBUG
		printf("squeue create error!\n");
		#endif
		return -1;
	}
	
	if((queue->rear+1)%N == queue->front)
		return 1;
	else
		return 0;
}

三、链表队列

>1、链表队列的原理

插入操作队尾进行,删除操作队头进行,由队头指针和队尾指针控制队列的操作。
在这里插入图片描述

因此链表队列结构体定义为:

#define DEBUG 1

typedef int data_t;
typedef struct node
{
	data_t data;
	struct node *next;
}linklist_t,*linklist;
typedef struct 
{
	linklist front,rear;
}listqueue,*linkqueue;

>2、链表队列的操作演示

在这里插入图片描述


>3、链表队列的创建

/**
 * @description: 链表队列创建
 * @param {*}
 * @return {lq-链表队列地址}
 */
linkqueue linkqueue_create()
{
	linkqueue lq = (linkqueue)malloc(sizeof(listqueue)); 
	if(lq  == NULL)
	{
		#if DEBUG
		printf("linkqueue create error!\n");
		#endif
		return 0;
	}

	lq->front = lq->rear = (linklist)malloc(sizeof(linklist_t));
	if(lq->front == NULL || lq->rear == NULL)
	{	
		#if DEBUG
		printf("linkqueue create error!\n");
		#endif
		return 0;
	}

	lq->front->data = 0;
	lq->front->next = NULL;

	return lq;
}

>4、链表队列的入队

/**
 * @description: 链表队列入队
 * @param {linkqueue} lq-链表队列指针
 * @param {data_t} value-入队列的值
 * @return {0-函数失败,1-函数成功}
 */
int linkqueue_enter(linkqueue lq, data_t value)
{
	linklist node = (linklist)malloc(sizeof(linklist_t));
	if(lq == NULL)
	{
		#if DEBUG
		printf("lq is NULL!\n");
		#endif
		return 0;
	}
	if(node == NULL)
	{	
		#if DEBUG
		printf("node create error!\n");
		#endif
		return 0;
	}

	lq->rear->next = node;
	lq->rear = node;
	node->data = value;
	node->next = NULL;

	return 1;
}

>5、链表队列的出队

/**
 * @description:链表队列出队 
 * @param {linkqueue} lq-链表队列指针
 * @return {0-函数失败,lq->front->data-出队列的值}
 */
data_t linkqueue_out(linkqueue lq)
{
	linklist node;
	if(lq == NULL)
	{
		#if DEBUG
		printf("lq is NULL!\n");
		#endif
		return 0;
	}
	if(lq->front == lq->rear)
	{
		#if DEBUG
		printf("lq is empty!\n");
		#endif
		return 0;
	}

	node = lq->front;
	lq->front = node->next;
	free(node);

	return lq->front->data;
}

>6、链表队列的释放

/**
 * @description: 链表队列释放
 * @param {linkqueue} lq-链表队列指针
 * @return {0-函数失败,1-函数成功}
 */
int linkqueue_free(linkqueue lq)
{
	linklist node;
	if(lq == NULL)
	{
		#if DEBUG
		printf("lq is NULL!\n");
		#endif
		return 0;
	}

	while(lq->front)
	{
		node = lq->front;
		lq->front = node->next;
		free(node);
	}
	free(lq);

	return 1;
}

>7、链表队列的清空

/**
 * @description: 链表队列清空
 * @param {linkqueue} lq-链表队列指针
 * @return {0-函数失败,1-函数成功}}
 */
int linkqueue_clear(linkqueue lq)
{
	linklist node;
	if(lq == NULL)
	{
		#if DEBUG
		printf("lq is NULL!\n");
		#endif
		return 0;
	}

	while(lq->front != lq->rear)
	{
		node = lq->front;
		lq->front = node->next;
		free(node);
	}

	return 1;
}

>8、判断链表队列是否为空

/**
 * @description:判断链表队列是否为空 
 * @param {linkqueue} lq-链表队列指针
 * @return {-1-函数失败,1-队列为空,0-队列不为空}
 */
int linkqueue_empty(linkqueue lq)
{
	if(lq == NULL)
	{
		#if DEBUG
		printf("lq is NULL!\n");
		#endif
		return -1;
	}
	
	return lq->front == lq->rear? 1:0;
}

四、链表的应用–球钟问题

1、球钟简介

钟是一个利用球的移动记录时间的简单装置

它有三个可以容纳若干个球的指示器:分钟指示器五分钟指示器小时指示器

若分钟指示器中有2个球,五分钟指示器中有6个球,小时指示器中有5个球,则时间为5:32


2、球钟工作原理

  • 每过一分钟,球钟就会从球队列队首取出一个球放入分钟指示器,分钟指示器最多可容纳4个球
  • 当放入第五个球时,在分钟指示器的4个球就会按照他们被放入时相反顺序加入球队列的队尾。而第五个球就会进入五分钟指示器
  • 按此类推,五分钟指示器最多可放11个球小时指示器最多可放11个球

3、问题阐述

  • 小时指示器放入第12个球时,原来的11个球按照他们被放入时相反顺序加入球队列的队尾,然后第12个球也回到队尾
  • 这时,三个指示器均为空,回到初始状态,从而形成一个循环。因此,该球钟表示时间的范围是从0:00到11:59

问题:
现设初始时球队列的球数为27,球钟的三个指示器初态均为空。要经过多久,球队列才能恢复原来的顺序


4、程序实现

这个问题我们选择顺序栈来作为指示器,链表队列作为球队列。实现代码如下:

/*
 * @Author: your name
 * @Date: 2022-03-11 16:23:40
 * @LastEditTime: 2022-03-11 18:37:53
 * @LastEditors: your name
 * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 * @FilePath: \ballclock\test.c
 */
#include "linkqueue.h"
#include "sqstack.h"

int queue_check(linkqueue lq); //检查是否队列为有序队列

int main(int argc, const char *argv[])
{
	linkqueue lq;
	int i, min = 0;
	data_t value;
	sqstack *s_hour,*s_five,*s_min;

	lq = linkqueue_create();
	if(lq == NULL)
		return 0;

	s_hour = stack_create(11);  //创建储存小时球的栈
	if(s_hour == NULL)
		return 0;

	s_five = stack_create(11);  //创建储存5分钟球的栈
	if(s_five == NULL)
		return 0;

	s_min = stack_create(4);   //创建储存分钟球的栈
	if(s_min == NULL)
		return 0;

	for(i = 1; i < 28; i++)  //将27颗数字球放入队列内
	{
		linkqueue_enter(lq, i);	
	}
	while(1)
	{
		min++;
		value = linkqueue_out(lq);  //一分钟后取出一颗球
		if(!stack_full(s_min))  //若分钟栈没满
			stack_push(s_min, value);  //存入分钟栈内
		else 
		{
			while(!stack_empty(s_min))  //分钟栈满了,取出栈内所有球
				linkqueue_enter(lq, stack_pop(s_min));
			if(!stack_full(s_five))  //若5分钟栈没满,下面步骤与上面类似
				stack_push(s_five, value);
			else
			{
				while(!stack_empty(s_five))
					linkqueue_enter(lq, stack_pop(s_five));
				if(!stack_full(s_hour))
					stack_push(s_hour, value);
				else
				{
					while(!stack_empty(s_hour))
						linkqueue_enter(lq, stack_pop(s_hour));
					linkqueue_enter(lq, value);
					if(queue_check(lq))  //检查是否队列为有序队列
						break;
				}
			}
		}
	}
	printf("min=%d\n",min);  //得到回归初始状态需要多少分钟
	while(!linkqueue_empty(lq))  //打印出队列值
	{
		printf("%d ",linkqueue_out(lq));
	}
	puts("");

	linkqueue_free(lq);
	stack_free(s_min);
	stack_free(s_five);
	stack_free(s_hour);

	return 0;
}

int queue_check(linkqueue lq)
{
	linklist p;
	if(lq == NULL)
	{
		printf("lq is NULL\n");
		return 0;
	}

	p = lq->front->next;
	if(p == NULL || p->next == NULL) //若队列没有值或者只有一个值
		return 0;
	while(p->next)
	{
		if(p->data > p->next->data)
			return 0;
		p = p->next;
	}
	return 1;
}

到这里就结束啦!
这里给出免费完整代码的下载链接:
队列C程序实现


在这里插入图片描述

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-03-12 17:47:47  更:2022-03-12 17:47:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 13:37:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码