【数据结构】队列——顺序实现+链式实现(带头结点+不带头结点)入队 出队 初始化 判空 双端队列 完整代码

news2024/9/25 13:24:28

文章目录

  • 四 队列
    • 1.基本概念
    • 2.队列的顺序存储
    • 3.队列的链式实现
      • 3.1 定义
      • 3.2 带头结点
        • 3.2.1 初始化
        • 3.2.2 判空
        • 3.2.3 入队
        • 3.2.4 出队
        • 3.2.5 完整代码
      • 3.3 不带头结点
        • 3.3.1 初始化
        • 3.3.2 入队
        • 3.3.3 出队
        • 3.3.4 完整代码
    • 4.双端队列

四 队列

1.基本概念

  • 定义

    只允许在一端进行插入,在另一端删除的线性表。

  • 术语

    • 队头:允许删除的一端。
    • 队尾:允许插入的一端。
  • 特点:先进先出

2.队列的顺序存储

  • 定义

    #define MaxSize 10
    #define ElemType int
    //定义
    typedef struct {
    	ElemType data[MaxSize];//用静态数组存放队列元素
    	int front, rear;//队头指针和队尾指针
    }SqQueue;
    
  • 循环队列

    搞成循环队列可以节约存储空间。

    避免出现队尾指针Q.rear已经到MaxSize时,队头指针Q.front前有剩余空间的情况。

  • 在循环队列下,队列空的条件是

    Q.rear==Q.front

  • 在循环队列下,队列已满的条件是

    (Q.rear+1)%MaxSize==Q.front

    即尾指针加一等于头指针时,队列已满。

    注:此时会浪费一个存储空间(队尾指针没有存数据)。

    • 如果不浪费,即尾指针rear也存元素,则队满和队空判断条件相同,我们无法用逻辑表达区分两种情况。

  • 如果题目要求不能浪费一点点存储空间,则将队列定义为

    typedef struct {
    	ElemType data[MaxSize];//用静态数组存放队列元素
    	int front, rear;//队头指针和队尾指针
        int size;//队列大小
    }SqQueue;
    
    • 此时队满条件:size==MaxSize
    • 队空条件:size==0
  • 完整代码

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

#define MaxSize 10
#define ElemType int

//定义
typedef struct {
	ElemType data[MaxSize];//用静态数组存放队列元素
	int front, rear;//队头指针和队尾指针
}SqQueue;

//初始化队列
void InitQueue(SqQueue& Q)
{
	//初始时,队头队尾指针都指向0
	Q.front = Q.rear = 0;
}

//判空
bool QueueEmpty(SqQueue Q)
{
	if (Q.rear == Q.front)
		return true;
	else
		return false;
}

//创建
bool CreatQueue(SqQueue& Q)
{
	int n = 5;
	srand(time(0));
	while (n--)
	{
		//队满则报错
		//队满条件:队尾指针的下一个位置是队头
		if ((Q.rear + 1) % MaxSize == Q.front)
			return false;
		Q.data[Q.rear] = rand() % 100 + 1;//新元素插入队尾
		//将存储空间在逻辑上变成环状(循环队列)
		Q.rear = (Q.rear + 1) % MaxSize;//队尾指针加1取模
	}
	return true;
}

//入队
bool EnQueue(SqQueue& Q, ElemType x)
{
	//队满则报错
	//队满条件:队尾指针的下一个位置是队头
	if ((Q.rear + 1) % MaxSize == Q.front)
		return false;
	Q.data[Q.rear] = x;//新元素插入队尾
	//将存储空间在逻辑上变成环状(循环队列)
	Q.rear = (Q.rear + 1) % MaxSize;//队尾指针加1取模
	return true;
}

//出队
bool DeQueue(SqQueue& Q, ElemType& x)
{
	//判空
	if (Q.rear == Q.front)return false;

	x = Q.data[Q.front];//x存出队的元素
	Q.front = (Q.front + 1) % MaxSize;//头指针后移
	return true;
}

//获取队头元素,用x返回
bool GetHead(SqQueue Q, ElemType& x)
{
	if (Q.rear == Q.front)return false;

	x = Q.data[Q.front];
	return true;
}

void QPrint(SqQueue Q) 
{
	for (int i = Q.front; i < Q.rear-1; i=(i+1) % MaxSize)
	{
		printf("%d,", Q.data[i]);
	}
	printf("%d\n", Q.data[Q.rear-1]);
}


int main()
{
	SqQueue Q;
	InitQueue(Q);

	printf("创建:\n");
	CreatQueue(Q);
	QPrint(Q);
	printf("\n");

	printf("请输入入队元素:\n");
	int x;
	scanf_s("%d", &x);
	EnQueue(Q, x);
	QPrint(Q);
	printf("\n");

	int y;
	DeQueue(Q, y);
	printf("出队元素:%d\n", y);
	QPrint(Q);
	printf("\n");

	int z;
	GetHead(Q, z);
	printf("队头元素:%d\n", z);
}

3.队列的链式实现

3.1 定义

分两个结构体

1.节点结构体:存节点数据和下一个节点地址。

2.队列结构体:存队列的头尾指针。

//定义
//链式队列节点
typedef struct LinkNode {
	ElemType data;
	struct LinkNode* next;
}LinkNode;
//链式队列
typedef struct {
	LinkNode* front;//指向队列队头的指针
	LinkNode* rear;//指向队列队尾的指针
}LinkQueue;
  • 可分为带头结点和不带头结点,两者功能差不多,具体看题目要求选哪个。
  • 因为是链表,所以不存在队满的时候,也不需要用循环队列。

3.2 带头结点

3.2.1 初始化

1.创建一个头节点;

2.将头尾指针front和rear都指向头节点;

3.头节点的next赋空值NULL。

//初始化队列
void InitQueue(LinkQueue& Q)
{
	//初始时 front、rear都指向头结点
	Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));
	Q.front->next = NULL;
}

3.2.2 判空

当头尾指针都指向同一节点时,链表为空。

//判空
bool IsEmpty(LinkQueue& Q)
{
	if (Q.front == Q.rear)
		return true;
	else
		return false;
}

3.2.3 入队

  • 步骤

    1.创建新节点,存数据+初始化指针域。

    2.新节点插入到原rear之后。

    3.更新rear,即使尾结点指向新插入节点。

void EnQueue(LinkQueue& Q, ElemType x)
{
	LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
	s->data = x;
	s->next = NULL;
	Q.rear->next = s;//新节点插入到rear之后
	Q.rear = s;//修改表尾指针
}

3.2.4 出队

根据队列中是否只有一个结点分两种情况。

  • 有多个结点时

    1.头结点和出队结点的下一个结点相连。

    2.释放出队结点。

  • 只有一个结点时

    1.尾结点指向头结点。

    2.释放出队结点。

    • 此时相当于空队列。

bool DeQueue(LinkQueue& Q, ElemType& x)
{
	//空队
	if (Q.front == Q.rear)return false;
	LinkNode* p = Q.front->next;
	x = p->data;//用变量x返回队头元素
	Q.front->next = p->next;//修改头指针的next指针,即连上出队节点的下一个节点
	//如果出队节点是尾节点,即队列中只有一个节点
	if (Q.rear == p)
		Q.rear = Q.front;//变成空队列
	free(p);//释放出队节点
	return true;
}

3.2.5 完整代码

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

#define ElemType int

//定义
//链式队列节点
typedef struct LinkNode {
	ElemType data;
	struct LinkNode* next;
}LinkNode;
//链式队列
typedef struct {
	LinkNode* front;//指向队列队头的指针
	LinkNode* rear;//指向队列队尾的指针
}LinkQueue;

//初始化队列
void InitQueue(LinkQueue& Q)
{
	//初始时 front、rear都指向头结点
	Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));
	Q.front->next = NULL;
}

//判空
bool IsEmpty(LinkQueue& Q)
{
	if (Q.front == Q.rear)
		return true;
	else
		return false;
}

//创建
bool CreatQueue(LinkQueue& Q)
{
	int n = 5;
	srand(time(0));
	while (n--)
	{
		LinkNode* t = (LinkNode*)malloc(sizeof(LinkNode));
		t->data = rand() % 100 + 1;
		t->next = NULL;
		Q.rear->next = t;
		Q.rear = t;
	}
	return true;
}

//新元素入队
void EnQueue(LinkQueue& Q, ElemType x)
{
	LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
	s->data = x;
	s->next = NULL;
	Q.rear->next = s;//新节点插入到rear之后
	Q.rear = s;//修改表尾指针
}

//出队
//用x返回元素
bool DeQueue(LinkQueue& Q, ElemType& x)
{
	//空队
	if (Q.front == Q.rear)return false;
	LinkNode* p = Q.front->next;
	x = p->data;//用变量x返回队头元素
	Q.front->next = p->next;//修改头指针的next指针,即连上出队节点的下一个节点
	//如果出队节点是尾节点,即队列中只有一个节点
	if (Q.rear == p)
		Q.rear = Q.front;//变成空队列
	free(p);//释放出队节点
	return true;
}

void QPrint(LinkQueue&Q)
{
	LinkNode* p = Q.front->next;
	while (p != Q.rear)
	{
		printf("%d ", p->data);
		p = p->next;
	}
	printf("%d\n\n", Q.rear->data);
}

int main()
{
	LinkQueue Q;
	InitQueue(Q);

	CreatQueue(Q);
	QPrint(Q);

	printf("请输入要入队的元素:\n");
	int x;
	scanf_s("%d", &x);
	EnQueue(Q, x);
	QPrint(Q);

	int y;
	DeQueue(Q, y);
	printf("出队元素为:%d\n", y);
	QPrint(Q);
}

3.3 不带头结点

3.3.1 初始化

//初始化队列
void InitQueue(LinkQueue& Q)
{
	//初始时 front、rear都指向NULL
	Q.front = NULL;
	Q.rear = NULL;
}

3.3.2 入队

根据入队元素是否是队列中第一个结点分两种情况。

  • 如果入队结点是第一个结点

    则头尾指针都指向入队结点。

  • 如果不是

    则新结点插入到队尾结点之后,并更新队尾结点

void EnQueue(LinkQueue& Q, ElemType x)
{
	LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
	s->data = x;
	s->next = NULL;
	//在空队列中插入第一个元素
	if (Q.front == NULL)
	{
		Q.front = s;//队头队尾指针都指向第一个元素
		Q.rear = s;
	}
	else
	{
		Q.rear->next = s;//新节点插入到队尾节点之后
		Q.rear = s;//更新队尾节点
	}
}

3.3.3 出队

  • 如果是最后一个结点出队,则需要恢复成空队状态。
bool DeQueue(LinkQueue& Q, ElemType& x)
{
	//空队
	if (Q.front == NULL)
		return false;

	LinkNode* p = Q.front;//p指向此次出队的节点
	x = p->data;//用变量x返回队头元素
	Q.front = p->next;//头指针指向出队节点的下一个节点
	
	//如果是最后一个节点出队
	//恢复成空队状态
	if (Q.rear == p)
	{
		Q.front = NULL;//front指向NULL
		Q.rear = NULL;//rear指向NULL
	}
	free(p);//释放节点空间
	return true;
}

3.3.4 完整代码

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

#define ElemType int

//定义
//链式队列节点
typedef struct LinkNode {
	ElemType data;
	struct LinkNode* next;
}LinkNode;
//链式队列
typedef struct {
	LinkNode* front;//指向队列队头的指针
	LinkNode* rear;//指向队列队尾的指针
}LinkQueue;

//初始化队列
void InitQueue(LinkQueue& Q)
{
	//初始时 front、rear都指向NULL
	Q.front = NULL;
	Q.rear = NULL;
}
//判空
bool IsEmpty(LinkQueue& Q)
{
	if (Q.front == NULL)
		return true;
	else
		return false;
}

//创建
bool CreatQueue(LinkQueue& Q)
{
	int n = 5;
	srand(time(0));
	while (n--)
	{
		LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
		s->data = rand() % 100 + 1;
		s->next = NULL;
		//在空队列中插入第一个元素
		if (Q.front == NULL)
		{
			Q.front = s;//队头队尾指针都指向第一个元素
			Q.rear = s;
		}
		else
		{
			Q.rear->next = s;//新节点插入到队尾节点之后
			Q.rear = s;//更新队尾节点
		}
	}
	return true;
}

//入队
void EnQueue(LinkQueue& Q, ElemType x)
{
	LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
	s->data = x;
	s->next = NULL;
	//在空队列中插入第一个元素
	if (Q.front == NULL)
	{
		Q.front = s;//队头队尾指针都指向第一个元素
		Q.rear = s;
	}
	else
	{
		Q.rear->next = s;//新节点插入到队尾节点之后
		Q.rear = s;//更新队尾节点
	}
}

//出队
bool DeQueue(LinkQueue& Q, ElemType& x)
{
	//空队
	if (Q.front == NULL)
		return false;

	LinkNode* p = Q.front;//p指向此次出队的节点
	x = p->data;//用变量x返回队头元素
	Q.front = p->next;//头指针指向出队节点的下一个节点
	
	//如果是最后一个节点出队
	//恢复成空队状态
	if (Q.rear == p)
	{
		Q.front = NULL;//front指向NULL
		Q.rear = NULL;//rear指向NULL
	}
	free(p);//释放节点空间
	return true;
}

void QPrint(LinkQueue& Q)
{
	LinkNode* p = Q.front;
	while (p != Q.rear)
	{
		printf("%d ", p->data);
		p = p->next;
	}
	printf("%d\n\n", Q.rear->data);
}

int main()
{
	printf("不带头节点:\n");

	LinkQueue Q;
	InitQueue(Q);

	CreatQueue(Q);
	QPrint(Q);

	printf("请输入要入队的元素:\n");
	int x;
	scanf_s("%d", &x);
	EnQueue(Q, x);
	QPrint(Q);

	int y;
	DeQueue(Q, y);
	printf("出队元素为:%d\n", y);
	QPrint(Q);
}

4.双端队列

  • 定义

    允许从两端插入删除的线性表。

  • 衍生

    • 输出受限的双端队列

      只允许从一端插入,两端删除。

    • 输出受限的双端队列

      只允许从两端插入,一端删除。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/712798.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

代理服务器拒绝连接怎么办

在使用代理服务器时&#xff0c;有时我们可能会遇到代理服务器拒绝连接的问题。这种情况可能会阻止我们访问被封锁的内容或绕过地理限制。下面&#xff0c;我们来一起探讨一下。 1. 配置错误 代理服务器拒绝连接的一个常见原因是配置错误。请确保您已正确输入代理服务器的地址和…

64MHz 闪存STM32G0B1CEU6(STM32G0B1CCU6)STM32G0B1CBU6引脚配置图、32位微控制器

STM32G0B1 32位微控制器具有最高512KB嵌入式闪存和144kB RAM存储器。该器件采用48-UFQFPN 引脚封装。它支持USB全速主机/设备、集成USB Type-C控制器和收发器、FDCAN协议以及多达8个UART。 STM32G0 32位微控制器 (MCU) 适合用于消费、工业和家电领域的应用&#xff0c;并可随时…

el-carousel和el-image组合实现swiper左右滑动图片,点击某张图片放大预览的效果

<template><el-carousel class"image-swiper" :height"100%" :indicator-position"swiperItems.length < 1 ? none : ":arrow"swiperItems.length < 1 ? never : "><el-carousel-item v-for"(a, $i) in s…

尚硅谷Docker实战教程-笔记06【Docker容器数据卷】

尚硅谷大数据技术-教程-学习路线-笔记汇总表【课程资料下载】视频地址&#xff1a;尚硅谷Docker实战教程&#xff08;docker教程天花板&#xff09;_哔哩哔哩_bilibili 尚硅谷Docker实战教程-笔记01【理念简介、官网介绍、平台入门图解、平台架构图解】尚硅谷Docker实战教程-笔…

移动端H5实现自定义拍照界面

一、实现思路 手机端 H5 实现自定义拍照界面也可以使用 MediaDevices API 和 <video> 标签来实现。 首先&#xff0c;使用 MediaDevices.getUserMedia() 方法获取摄像头媒体流&#xff0c;并将其传递给 <video> 标签进行渲染。 接着&#xff0c;使用 HTML 的 <…

手把手教你搭建SpringCloudAlibaba之Sentinel注解SentinelResource

SpringCloud Alibaba全集文章目录&#xff1a; 零、手把手教你搭建SpringCloudAlibaba项目 一、手把手教你搭建SpringCloud Alibaba之生产者与消费者 二、手把手教你搭建SpringCloudAlibaba之Nacos服务注册中心 三、手把手教你搭建SpringCloudAlibaba之Nacos服务配置中心 …

【智慧交通项目实战】《 OCR车牌检测与识别》(四):基于Pyqt的项目可视化

&#x1f468;‍&#x1f4bb;作者简介&#xff1a; CSDN、阿里云人工智能领域博客专家&#xff0c;新星计划计算机视觉导师&#xff0c;百度飞桨PPDE&#xff0c;专注大数据与AI知识分享。✨公众号&#xff1a;GoAI的学习小屋 &#xff0c;免费分享书籍、简历、导图等&#xf…

SpringBoot 限流方案

一、背景 限流对于一个微服务架构系统来说具有非常重要的意义&#xff0c;否则其中的某个微服务将成为整个系统隐藏的雪崩因素&#xff0c;为什么这么说&#xff1f; 举例来讲&#xff0c;某个SAAS平台有100多个微服务应用&#xff0c;但是作为底层的某个或某几个应用来说&…

【前端】运行一个vue项目

如何运行一个vue项目 首先cd到要运行的vue文件夹下&#xff0c;或者是在webstorm下面的终端直接打开&#xff0c;就会自动开启在这个文件夹下的终端安装项目中所有需要的依赖包 sudo npm install运行项目 sudo npm run serve到这里项目就运行起来了 4. 打开项目 点击网址打…

html实现视频网站,仿爱奇艺,搜狐,迅雷看看(附源码)

文章目录 1.功能模板1.1 仿爱奇艺1.2 仿搜狐视频1.3 仿迅雷看看1.4 视频播放1.5 影视公司官网 2.效果和源码2.1 源代码2.2 模板目录 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/131516313 html实现视频网站…

c++ 内存管理二:重载(接管内存管理工具)

文章目录 前言1 重载全局的 ::operator new 运算符2 重载类的 operator new 运算符3 重载类的带有额外参数的 operator new 运算符 前言 重载 operator new 运算符来自定义内存分配的行为。重载 operator new 运算符允许我们使用自定义的内存分配逻辑&#xff0c;例如使用池分…

压测工具哪个好?LoadRunner、Jmeter、Locust、Wrk 全方位对比....

当你想做性能测试的时候&#xff0c;你会选择什么样的测试工具呢&#xff1f;是会选择wrk&#xff1f;jmeter&#xff1f;locust&#xff1f;还是loadrunner呢&#xff1f;今天&#xff0c;笔者将根据自己使用经验&#xff0c;针对jmeter、locust、wrk和loadrunner常用的性能测…

【数据结构与算法】内排序算法比较(C\C++)

实践要求 1. 问题描述 各种内部排序算法的时间复杂度分析结果只给出了算法执行时间的阶&#xff0c;或大概执行时间&#xff0c;试通过随机的数据比较各算法的关键字比较次数和关键字移动次数&#xff0c;以取得直观感受。 2. 基本要求 对以下10种常用的内部排序算法进行比较…

MySQL更改表结构语句

一、MySQL表结构变更语句 1. 新增字段 语法&#xff1a; &#xff08;1&#xff09;在末尾添加字段 ALTER TABLE <表名> ADD <新字段名><数据类型>[约束条件]; &#xff08;2&#xff09;在开头添加字段 ALTER TABLE <表名> ADD <新字段名> <…

[C++]lambda

目录 前言&#xff1a; 1 认识lambda 2 lambda语法 3 lambda的类型 4 lambda的底层 前言&#xff1a; 本篇讲解了C11当中新添加的lambda语法&#xff0c;以及lambda的底层 1 认识lambda lambda的出现方便了很多我们写程序的地方&#xff0c;例如下面这个样例…

C++图形开发(2):最基本的图形界面

文章目录 1.构成2.内容介绍2.1 initgraph()2.2 _getch()2.3 closegraph() 3.总结 今天来简单介绍下最基本的图形界面~ 1.构成 输入以下内容并编译&#xff1a; 这就是一个最基本的图形界面了 #include<graphics.h> #include<conio.h>int main() {initgraph(600, …

rollup入门 - 学习笔记(1)

rollup打包工具 打包项目用webpack , 打包js库用rollup 下载rollup npm i rollup --save-dve 初始化项目 npm init -y 创建src/main.js文件 import welcomerollup from ../modules/mymodule welcomerollup(hello world) 创建module/mymodule.js文件 const welcomerollup (ms…

Python PDF生成和二进制流转换(FPDF)

文章目录 安装FPDF生成PDF文档生成PDF的二进制流 安装FPDF pip install fpdf22.7.4生成PDF文档 通过FPDF生成PDF文档的具体步骤&#xff1a; 初始化&#xff1a;fpdf库的操作主要由FPDF对象来处理&#xff0c;在生成PDF文档时&#xff0c;需要初始化FPDF对象。添加页面&…

引爆媒体关注的秘密武器:媒介易教你打造热门新闻故事!

在进行媒体邀约时&#xff0c;提供有吸引力的新闻价值和故事性是吸引媒体关注和获得采访机会的关键。媒体记者时常接收大量的邀约&#xff0c;因此需要与众多企业竞争&#xff0c;才能让自己的邀约脱颖而出。本文将探讨如何在媒体邀约中提供有吸引力的新闻价值和故事性&#xf…

Domain Admin域名和SSL证书过期监控到期提醒

基于Python3 Vue3.js 技术栈实现的域名和SSL证书监测平台 用于解决&#xff0c;不同业务域名SSL证书&#xff0c;申请自不同的平台&#xff0c;到期后不能及时收到通知&#xff0c;导致线上访问异常&#xff0c;被老板责骂的问题 核心功能&#xff1a;域名 和SSL证书 的过期…