数据结构与算法教程,数据结构C语言版教程!(第三部分、栈(Stack)和队列(Queue)详解)四

 第三部分、栈(Stack)和队列(Queue)详解

栈和队列,严格意义上来说,也属于线性表,因为它们也都用于存储逻辑关系为 "一对一" 的数据,但由于它们比较特殊,因此将其单独作为一章,做重点讲解。

使用栈结构存储数据,讲究“先进后出”,即最先进栈的数据,最后出栈;使用队列存储数据,讲究 "先进先出",即最先进队列的数据,也最先出队列。

既然栈和队列都属于线性表,根据线性表分为顺序表和链表的特点,栈也可分为顺序栈和链表,队列也分为顺序队列和链队列,这些内容都会在本章做详细讲解。

七、什么是队列(队列存储结构)

队列,和栈一样,也是一种对数据的"存"和"取"有严格要求的线性存储结构。

与栈结构不同的是,队列的两端都"开口",要求数据只能从一端进,从另一端出,如图 1 所示:

队列存储结构

图 1 队列存储结构

通常,称进数据的一端为 "队尾"出数据的一端为 "队头",数据元素进队列的过程称为 "入队",出队列的过程称为 "出队"。

不仅如此,队列中数据的进出要遵循 "先进先出" 的原则,即最先进队列的数据元素,同样要最先出队列。拿图 1 中的队列来说,从数据在队列中的存储状态可以分析出,元素 1 最先进队,其次是元素 2,最后是元素 3。此时如果将元素 3 出队,根据队列 "先进先出" 的特点,元素 1 要先出队列,元素 2 再出队列,最后才轮到元素 3 出队列。

栈和队列不要混淆,栈结构是一端封口,特点是"先进后出";而队列的两端全是开口,特点是"先进先出"。

因此,数据从表的一端进,从另一端出,且遵循 "先进先出" 原则的线性存储结构就是队列。

队列存储结构的实现有以下两种方式:

  1. 顺序队列:在顺序表基础上实现的队列结构;
  2. 链队列:在链表的础上实现的队列结构;

两者的区别仅是顺序表和链表的区别,即在实际的物理空间中,数据集中存储的队列是顺序队列,分散存储的队列是链队列。

实际生活中,队列的应用随处可见,比如排队买 XXX、医院的挂号系统等,采用的都是队列的结构。

拿排队买票来说,所有的人排成一队,先到者排的就靠前,后到者只能从队尾排队等待,队中的每个人都必须等到自己前面的所有人全部买票成功并从队头出队后,才轮到自己买票。这就不是典型的队列结构吗?

明白了什么是队列,接下来开始系统地学习顺序队列和链队列。


八、顺序队列及C语言实现(2种方案)

顺序队列即采用顺序表模拟实现的队列结构。

我们知道,队列具有以下两个特点:

  1. 数据从队列的一端进,另一端出;
  2. 数据的入队和出队遵循"先进先出"的原则;

因此,只要使用顺序表按以上两个要求操作数据,即可实现顺序队列。首先来学习一种最简单的实现方法。

1、顺序队列简单实现

由于顺序队列的底层使用的是数组,因此需预先申请一块足够大的内存空间初始化顺序队列。除此之外,为了满足顺序队列中数据从队尾进,队头出且先进先出的要求,我们还需要定义两个指针(top 和 rear)分别用于指向顺序队列中的队头元素和队尾元素,如图 1 所示:

顺序队列实现示意图

图 1 顺序队列实现示意图

由于顺序队列初始状态没有存储任何元素,因此 top 指针和 rear 指针重合,且由于顺序队列底层实现靠的是数组,因此 top 和 rear 实际上是两个变量,它的值分别是队头元素和队尾元素所在数组位置的下标。

在图 1 的基础上,当有数据元素进队列时,对应的实现操作是将其存储在指针 rear 指向的数组位置,然后 rear+1;当需要队头元素出队时,仅需做 top+1 操作。

例如,在图 1 基础上将 {1,2,3,4} 用顺序队列存储的实现操作如图 2 所示:

数据进顺序队列的过程实现示意图

图 2 数据进顺序队列的过程实现示意图

在图 2 基础上,顺序队列中数据出队列的实现过程如图 3 所示:

数据出顺序队列的过程示意图

图 3 数据出顺序队列的过程示意图

因此,使用顺序表实现顺序队列最简单方法的 C 语言实现代码为:

#include <stdio.h>

int enQueue(int *a,int rear,int data){

        a[rear]=data;

        rear++;

        return rear;

}

void deQueue(int *a,int front,int rear){

        //如果 front==rear,表示队列为空

        while (front!=rear) {

                printf("出队元素:%d\n",a[front]);

                front++;

        }

}

int main() {

        int a[100];

        int front,rear;

        //设置队头指针和队尾指针,当队列中没有元素时,队头和队尾指向同一块地址

        front=rear=0;

        //入队

        rear=enQueue(a, rear, 1);

        rear=enQueue(a, rear, 2);

        rear=enQueue(a, rear, 3);

        rear=enQueue(a, rear, 4);

        //出队

        deQueue(a, front, rear);

        return 0;

}

程序输出结果:

出队元素:1
出队元素:2
出队元素:3
出队元素:4

(1)此方法存在的问题

先来分析以下图 2b) 和图 3b)。图 2b) 是所有数据进队成功的示意图,而图 3b) 是所有数据全部出队后的示意图。通过对比两张图,你会发现,指针 top 和 rear 重合位置指向了  a[4] 而不再是 a[0]。也就是说,整个顺序队列在数据不断地进队出队过程中,在顺序表中的位置不断后移。

顺序队列整体后移造成的影响是:

  • 顺序队列之前的数组存储空间将无法再被使用,造成了空间浪费;
  • 如果顺序表申请的空间不足够大,则直接造成程序中数组 a 溢出,产生溢出错误;

为了避免以上两点,我建议初学者使用下面的方法实现顺序队列。

2、顺序队列另一种实现方法

既然明白了上面这种方法的弊端,那么我们可以试着在它的基础上对其改良。

为了解决以上两个问题,可以使用巧妙的方法将顺序表打造成一个环状表,如图 4 所示:

环状顺序队列

图 4 环状顺序队列

图 4 只是一个想象图,在真正的实现时,没必要真创建这样一种结构,我们还是使用之前的顺序表,也还是使用之前的程序,只需要对其进行一点小小的改变:

#include <stdio.h>

#define max 5//表示顺序表申请的空间大小

int enQueue(int *a,int front,int rear,int data){

        //添加判断语句,如果rear超过max,则直接将其从a[0]重新开始存储,如果rear+1和front重合,则表示数组已满

        if ((rear+1)%max==front) {

                printf("空间已满");

                return rear;

        }

        a[rear%max]=data;

        rear++;

        return rear;

}

int deQueue(int *a,int front,int rear){

        //如果front==rear,表示队列为空

        if(front==rear%max) {

                printf("队列为空");

                return front;

        }

        printf("%d ",a[front]);

        //front不再直接 +1,而是+1后同max进行比较,如果=max,则直接跳转到 a[0]

        front=(front+1)%max;

        return front;

}

int main() {

        int a[max];

        int front,rear;

        //设置队头指针和队尾指针,当队列中没有元素时,队头和队尾指向同一块地址

        front=rear=0;

        //入队

        rear=enQueue(a,front,rear, 1);

        rear=enQueue(a,front,rear, 2);

        rear=enQueue(a,front,rear, 3);

        rear=enQueue(a,front,rear, 4);

        //出队

        front=deQueue(a, front, rear);

        //再入队

        rear=enQueue(a,front,rear, 5);

        //再出队

        front=deQueue(a, front, rear); /

        /再入队

        rear=enQueue(a,front,rear, 6);

        //再出队

        front=deQueue(a, front, rear);

        front=deQueue(a, front, rear);

        front=deQueue(a, front, rear);

        front=deQueue(a, front, rear);

        return 0;

}

程序运行结果:

1 2 3 4 5 6

使用此方法需要注意的是,顺序队列在判断数组是否已满时,出现下面情况:

  • 当队列为空时,队列的头指针等于队列的尾指针;
  • 当数组满员时,队列的头指针等于队列的尾指针;

顺序队列的存储状态不同,但是判断条件相同。为了对其进行区分,最简单的解决办法是:牺牲掉数组中的一个存储空间,判断数组满员的条件是:尾指针的下一个位置和头指针相遇,就说明数组满了,即程序中第 5 行所示。

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

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

相关文章

1.UnityProfiler性能分析提升性能

一 Stats重要参数详解 1.main thread 主线程 业务逻辑都在这里&#xff0c;我们调用Unity API都在这里&#xff1b;例如设置transform位置&#xff0c;main thread里面处理 2.render thread&#xff0c;渲染线程&#xff0c;负责渲染图像、执行渲染循环、处理GPU命令、帧同步。…

计算机网络系统结构-2020期末考试解析

【前言】 不知道为什么计算机网络一门课这么多兄弟&#xff0c;这份看着也像我们的学科&#xff0c;所以也做了。 一&#xff0e; 单选题&#xff08;每题 2 分&#xff0c;共 20 题&#xff0c;合计 40 分&#xff09; 1 、当数据由主机 A 发送到主机 B &#xff0c;不参…

机器学习_7、KNN

数据采用&#xff1a;电离层数据 KNN完整的代码电离层数据资源-CSDN文库 代码 import os import csv import numpy as np from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsClassifier from sklearn.model_selection import …

ChatGPT可以帮你做什么?

学习 利用ChatGPT学习有很多&#xff0c;比如&#xff1a;语言学习、编程学习、论文学习拆解、推荐学习资源等&#xff0c;使用方法大同小异&#xff0c;这里以语言学习为例。 在开始前先给GPT充分的信息&#xff1a;&#xff08;举例&#xff09; 【角色】充当一名有丰富经验…

【分布式微服务专题】从单体到分布式(四、SpringCloud整合Sentinel)

目录 前言阅读对象阅读导航前置知识一、什么是服务雪崩1.1 基本介绍1.2 解决方案 二、什么是Sentinel2.1 基本介绍2.2 设计目的2.3 基本概念 三、Sentinel 功能和设计理念3.1 流量控制3.2 熔断降级3.3 系统负载保护 四、Sentinel 是如何工作的 笔记正文一、简单整合Sentinel1.1…

Zynq 电源

ZYNQ芯片的电源分PS系统部分和PL逻辑部分&#xff0c;两部分的电源分别是独立工作。PS系统部分的电源和PL逻辑部分的电源都有上电顺序&#xff0c;不正常的上电顺序可能会导致ARM系统和FPGA系统无法正常工作。 PS部分的电源有VCCPINT、VCCPAUX、VCCPLL和PS VCCO。 VCCPINT为PS内…

便捷好用的iOS文件管理App

便捷好用的iOS文件管理App 摘要 本文介绍了一款功能强大、免费的iOS文件管理App——克魔助手。通过使用克魔助手&#xff0c;用户可以轻松管理手机存储空间&#xff0c;清理垃圾文件&#xff0c;整理文件&#xff0c;并进行文件传输和截图操作。本文将详细介绍克魔助手的各项…

使用Sqoop将数据导入Hadoop的详细教程

在大数据处理中&#xff0c;Sqoop是一个强大的工具&#xff0c;它可以将关系型数据库中的数据导入到Hadoop生态系统中&#xff0c;以便进行进一步的分析和处理。本文将提供一个详细的教程&#xff0c;以帮助大家了解如何使用Sqoop将数据导入Hadoop。 准备工作 在开始之前&…

代码随想录 Leetcode707. 设计链表

题目&#xff1a; 代码(首刷看解析 2024年1月11日&#xff09;&#xff1a; class MyLinkedList { private:struct ListNode{int val;ListNode* next;ListNode(int val):val(val),next(nullptr){}};int size;ListNode* dummyHead; public:MyLinkedList() {dummyHead new List…

【算法】增减序列(贪心,差分)

题目 给定一个长度为 n 的数列 a1,a2,…,an&#xff0c;每次可以选择一个区间 [l,r]&#xff0c;使下标在这个区间内的数都加一或者都减一。 求至少需要多少次操作才能使数列中的所有数都一样&#xff0c;并求出在保证最少次数的前提下&#xff0c;最终得到的数列可能有多少种…

机器人制作开源方案 | 六足灾后探测机器人

作者&#xff1a;毕钟诚 施钥 范江龙 张莉曼 陈金凤 单位&#xff1a;中国石油大学&#xff08;北京&#xff09; 指导老师&#xff1a;许亚岚 孙琳 世纪全球自然灾害频发&#xff0c;灾后探测重建工作十分重要&#xff0c;极端恶劣的现场探测环境&#xff0c;频发的余震甚至…

羊驼2:开放的基础和微调聊天模型--Llama 2论文阅读

论文地址&#xff1a;https://arxiv.org/pdf/2307.09288.pdfd 代码地址&#xff1a;GitHub - facebookresearch/llama-recipes: Examples and recipes for Llama 2 model 问答 用了多少个gpu&#xff1f; 这篇文档中使用了3.3M GPU小时的计算&#xff0c;使用的硬件类型是A…

H 指数,经典算法实战。

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

【java八股文】之Java基础篇

1、Java有哪几种数据类型 基本数据类型&#xff1a;byte(1字节) short&#xff08;2字节&#xff09; int&#xff08;4字节&#xff09; long&#xff08;8字节&#xff09; float&#xff08;4字节&#xff09; double&#xff08;8字节&#xff09; char&#xff08;2字节&a…

写点东西《Docker入门(下)》

写点东西《Docker入门(下)》 Docker ComposeDocker 注册表Docker 引擎Linux 容器和 Windows 容器的概念:容器编排Docker SwarmDocker Compose Docker Compose 是一个方便的工具,可帮助您轻松运行和连接不同的软件服务,就好像它们都是同一事件的一部分一样。 Docker Compo…

[电影] - 恶人传(韩)

英文片名&#xff1a;The Gangster The Cop The Devil 黑帮老大开了地下游戏厅&#xff0c;贿赂了警察队长。警察主角是刑警二组组长&#xff0c;还是去游戏厅搜查。 警察主角抓了个比较搞笑的黄毛&#xff1a; 警察队长&#xff0c;有个专门电话和黑帮联络的&#xff1a; 两个…

【Python】编程练习的解密与实战(三)

​&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《Python | 编程解码》⏰诗赋清音&#xff1a;云生高巅梦远游&#xff0c; 星光点缀碧海愁。 山川深邃情难晤&#xff0c; 剑气凌云志自修。 目录 &#x1fa90;1. 初识Python &a…

Tensorflow和飞桨Paddle的控制流算子设计

一、概览 注&#xff1a;整体方案上尚存在技术疑点&#xff0c;需进一步小组内讨论对齐&#xff0c;避免方案设计上存在后期难以扩展&#xff08;或解决&#xff09;的局限性 框架TensorFlow 1.xTensorFlow 2.xPaddlecond/while√√√实现机制组合OP (DataFlow)函数式 (Functio…

Alphalens因子分析(4) - Information Coefficient方法

在前面的笔记中&#xff0c;无论是回报分析&#xff0c;还是因子Alpha&#xff0c;它们都受到交易成本的影响。信息分析 (Information Analysis)则是一种不受这种影响的评估方法&#xff0c;主要研究方法就是信息系数(Information Coefficient)。 信息系数的范围为-1到1&#x…

linux 02 vmware的快照,文件管理

01.快照 使用快照&#xff1a; 同时的快照管理器&#xff1a; 如果想要返回快照&#xff0c;选择要选择的快照&#xff0c;跳转 02. 文件管理&#xff1a; cd 修改当前路径 02.touch 创建文件 03. mkdir 创建文件夹 mkdir -p 文件夹 &#xff08;创建之前没有的上级文件…