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

【数据结构】栈和队列的模拟实现(两个方式实现)

前言

💓作者简介: 加油,旭杏,目前大二,正在学习C++数据结构等👀
💓作者主页:加油,旭杏的主页👀

⏩本文收录在:再识C进阶的专栏👀

🚚代码仓库:旭日东升 1👀

🌹欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖

学习目标:

       这一篇博客将学习栈和队列的相关知识,队列是两种基础的数据结构,在现在一定要打好基础,在之后的学习生涯中,也常常遇见,例如:深度优先搜索(DFS)广度优先搜索(BFS)……今天要学习栈和队列的模拟实现:数组模拟实现栈,用单链表模拟实现队列,用数组模拟实现队列。


学习内容:

通过上面的学习目标,我们可以列出要学习的内容:

  1. 用数组模拟实现栈
  2. 用数组模拟实现队列
  3. 用单链表模拟实现队列

一、栈的相关知识

1.1 栈的概念及结构

下面先来一段大白话,在介绍栈的文章中都会出现的。

       栈是一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作(类似于尾插尾删)。我们先来介绍两个概念——栈顶与栈底:进行数据插入和删除操作的一端为栈顶,而另一端为栈底。高大上一点的叫法是:栈中的元素遵守后进先出LIFO(Last In First Out)的原则。

下面,我们在来介绍两个操作——圧栈与入栈:

  • 压栈:栈的插入操作是进栈/压栈/入栈,入数据在栈顶;
  • 出栈:栈的删除操作是出栈,出数据在栈顶。

1.2 栈的实现

       现在,我们学习了两个数据结构:顺序表与链表,到底用哪个数据结构实现栈比较好呢?在这里我们选用数组来模拟实现栈。

为什么我们要用数组模拟实现栈会更好一些?

       栈的两个操作无疑就是尾插与尾删,这两个操作在数组中都比较容易实现(相对于链表),而且数组存储的数据内容比较集中,CPU高速缓存命中率高,尽可能小地不污染缓存区,所以用数组模拟实现比较好一些。

       在现实生活中,我们一般要实现能够进行动态增长的栈,而不是静态的栈(比较死板,在实际应用中不常见)。虽然,静态的栈在实际生活中不常见,但是在算法题目中还是可以进行使用,而且在算法题中,我们不用考虑内存泄漏问题hh。下面来实现吧!

代码一:实现动态的栈

第一步,我们先来定义要使用的头文件:

#include <stdio.h>  //必须要包含的头文件
#include <assert.h> //要使用assert进行断言,防止出现一下不好的情况发生
#include <stdbool.h> //在C语言中,没有提供bool变量
#include <stdlib.h>  //使用一些申请内存空间的函数

第二步,我们要让主角登场,构造栈的结构体:

typedef int StDatatype; // 为了方便以后更改数组中的数据类型
typedef struct stack {StDatatype* a;  // 一个动态空间int top;   // 表示栈的栈顶int capacity; // 表示栈现在有多少空间
}ST;

第三步,我们要定义一些我们要实现栈功能的一些函数:栈的初始化(定义一个结构,一定要初始化成员变量)、栈的销毁、栈的插入操作、栈的删除操作、查看栈的栈顶元素、查看栈的大小、查看栈是否为空

//栈的初始化
void stackinit(ST* stk);
//栈的插入操作
void stackpush(ST* stk, StDatatype x);
//栈的删除操作
void stackpop(ST* stk);
//返回栈的栈顶元素
StDatatype stacktop(ST* stk);
//判断栈是否为空
bool stackempty(ST* stk);
//返回栈的大小
int stacksize(ST* stk);
//销毁栈
void stackdestroy(ST* stk);

栈的初始化操作:

void stackinit(ST* stk)
{assert(stk); //防止传空指针//有两个方式进行初始化//法1stk->a = NULL;stk->capacity = 0;stk->top = 0; //如果这里指向0,top表示的是栈的大小
}//法2
void stackinit(ST* stk)
{assert(stk);stk->a = NULL;stk->capacity = 0;stk->top = -1; //如果这里指向-1,top表示的是栈顶元素的下标
}

栈的销毁操作:

void stackdestroy(ST* stk)
{assert(stk);free(stk->a);stk->a = NULL; // 别忘记置空,防止野指针出现free(stk);stk = NULL;
}
// 因为栈所使用的是数组,所以直接销毁即可

栈的插入操作:

void stackpush(ST* stk, StDatatype x)
{assert(stk);//因为我们在这里的栈的空间是没有创建的if (stk->capacity == stk->top) {int newcapacity = stk->capacity == 0 ? 4 : stk->capacity * 2;StDatatype* tmp = (StDatatype*)realloc(stk->a, newcapacity * sizeof(StDatatype));if (tmp == NULL) {perror(tmp);return;}stk->a = tmp;stk->capacity = newcapacity;}
//插入操作相当于尾插stk->a[stk->top] = x;stk->top++;  // 别忘了栈顶要加1
}

栈的删除操作:

void stackpop(ST* stk)
{assert(stk);assert(stk->top > 0);stk->top--;
}

返回栈的栈顶元素:

StDatatype stacktop(ST* stk)
{assert(stk);assert(stk->top > 0);return stk->a[stk->top - 1]; // top == 0//return stk->a[stk->top];  // top == -1
}

 判断栈是否为空:

bool stackempty(ST* stk)
{
// 第一种写法:assert(stk);if (stk->top == 0){return true;}return false;
// 第二种写法://return stk->top == 0;
}

返回栈的大小:

int stacksize(ST* stk)
{assert(stk);return stk->top;  // top == 0//return stk->top + 1; // top == -1
}

代码二:实现静态的栈

struct my_stack
{int a[10];int size;int capacity;
}

二、队列的相关知识

2.1 队列的概念及结构

       队列在日常生活中无处不在,排队就是一种典型的队列。对此,我们大致可以得知:队列是只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出的性质。和栈一样,队列具有两个基本操作——入队和出队:

入队:进行插入操作的一端称为队尾;

出队:进行删除操作的一端称为队头。

2.2 队列的实现

       与实现栈类似,我们先来讨论一下使用哪种数据结构方便一些?是使用顺序表呢,还是使用链表呢?是使用单链表呢还是使用双向链表?

       分析一下队列的插入和删除操作,发现插入操作是尾插,而删除操作是头删。在实现顺序表和链表时,对于头删操作来说,链表更为简单,而顺序表需要进行移动数据,效率较低。因此,我们使用链表来实现操作。

代码一:链表实现队列

第一步,我们还是先将头文件加上:

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

第二步,我们来建立一下队列的数据结构:

typedef int QueDatatype;typedef struct queue {QueDatatype x;struct queue* next;
}Queue;//由于要用二级指针,并且我们还有多个成员,
//然后就用结构体typedef struct Qnode {Queue* phead;Queue* ptail;  // 存储链表的尾结点,方便于尾插int size;
}Qnode;

 第三步,我们来定义一下队列的功能:队列的初始化,队列的销毁,队列的插入操作,队列的删除操作,返回队列的队头元素,返回队列的大小,检查队列是否为空。

//队列初始化
void queueinit(Qnode* qnd);
//队列销毁
void queuedestroy(Qnode* qnd);
//队列的插入操作
void queuepush(Qnode* qnd, QueDatatype x);
//队列的删除操作
void queuepop(Qnode* qnd);
//队列的对头元素
QueDatatype queuefront(Qnode* qnd);
//队列的大小
int queuesize(Qnode* qnd);
//检查队列是否为空
bool quueueempty(Qnode* qnd);

队列的初始化操作:

void queueinit(Qnode* qnd)
{assert(qnd);qnd->phead = qnd->ptail = NULL;qnd->size = 0;
}

队列的销毁操作:

void queuedestroy(Qnode* qnd)
{assert(qnd);//销毁是要从头到尾进行销毁的Queue* cur = qnd->phead;while (cur){Queue* del = cur->next;free(cur);cur = del;}
// 只有一个结点的情况,会出现一个野指针qnd->phead = qnd->ptail = NULL;qnd->size = 0;
}

队列的插入操作:

void queuepush(Qnode* qnd, QueDatatype x)
{assert(qnd);//创建好了结构体,然后进行操作Queue* tmp = (Queue*)malloc(sizeof(Queue));//防止创建失败if (tmp == NULL){perror(tmp);return;}tmp->x = x;tmp->next = NULL;//将这个新结点链接到链表中if (qnd->phead == NULL){qnd->phead = qnd->ptail = tmp;}else {qnd->ptail->next = tmp;qnd->ptail = tmp;}qnd->size++;
}

队列的删除操作:

void queuepop(Qnode* qnd)
{assert(qnd);//头结点不能为空assert(qnd->phead);//其次,在只有一个结点的过程中,会出现野指针Queue* del = qnd->phead;qnd->phead = del->next;free(del);del = NULL;if (qnd->phead == NULL){qnd->ptail = NULL;}qnd->size--;
}

返回队列的队头元素:

QueDatatype queuefront(Qnode* qnd)
{assert(qnd);//不能队列为空assert(qnd->phead);return qnd->phead->x;
}

返回队列的大小:

int queuesize(Qnode* qnd)
{assert(qnd);return qnd->size;
}

检查队列是否为空:

bool quueueempty(Qnode* qnd)
{assert(qnd);//if (qnd->phead ==NULL)//{//	return true;//}//return false;return qnd->phead == NULL;
}

代码二:数组实现队列

int q[N], hh, tt = -1;

学习产出:

  1. 用数组模拟实现栈
  2. 用数组模拟实现队列
  3. 用单链表模拟实现队列

相关文章:

【数据结构】栈和队列的模拟实现(两个方式实现)

前言 &#x1f493;作者简介&#xff1a; 加油&#xff0c;旭杏&#xff0c;目前大二&#xff0c;正在学习C&#xff0c;数据结构等&#x1f440; &#x1f493;作者主页&#xff1a;加油&#xff0c;旭杏的主页&#x1f440; ⏩本文收录在&#xff1a;再识C进阶的专栏&#x1…...

OpenCV+相机校准和3D重建

相机校准至少需要10个测试图案&#xff0c;所需的重要输入数据是3D现实世界点集以及图像中这些点的相应2D坐标。3D点称为对象点&#xff0c;而2D图像点称为图像点。 准备工作 除了棋盘&#xff0c;我们还可以使用圆形网格。 在这种情况下&#xff0c;我们必须使用函数cv.find…...

2023.11.14-hive之表操作练习和文件导入练习

目录 需求1.数据库基本操作 需求2. 默认分隔符案例 需求1.数据库基本操作 -- 1.创建数据库test_sql,cs1,cs2,cs3 create database test_sql; create database cs1; create database cs2; create database cs3; -- 2.1删除数据库cs2 drop database cs2; -- 2.2在cs3库中创建…...

idea2023启动springboot项目如何指定配置文件

方法一&#xff1a; 方法二&#xff1a; 举例&#xff1a;...

在 uniapp 中 一键转换单位 (px 转 rpx)

在 uniapp 中 一键转换单位 px 转 rpx Uni-app 官方转换位置利用【px2rpx】插件Ctrl S一键全部转换下载插件修改插件 Uni-app 官方转换位置 首先在App.vue中输入这个&#xff1a; uni.getSystemInfo({success(res) {console.log("屏幕宽度", res.screenWidth) //屏…...

SQL对数据进行去重

工作中使用SQL对数据进行处理计算时可能会遇到这样的问题&#xff1b;读取的表数据会有重复&#xff0c;或者我们关注的几个字段的数据会有重复&#xff0c;直接使用原表数据会引起计算结果不准或者做表连接时产生笛卡尔积。 本文记录使用SQL进行数据去重的几种算法。 distinc…...

登录注册代码模板(Vue3+SpringBoot)[邮箱发送验证码(HTML)、RSA 加密解密(支持长文本)、黑暗与亮色主题切换、AOP信息校验]

文章归档&#xff1a;https://www.yuque.com/u27599042/coding_star/cx5ptule64utcr9e 仓库地址 https://gitee.com/tongchaowei/login-register-template 网页效果展示 相关说明 在该代码模板中&#xff0c;实现了如下功能&#xff1a; 邮箱发送验证码&#xff08;邮件内容…...

【计算机网络】VRRP协议理论和配置

目录 1、VRRP虚拟路由器冗余协议 1.1、协议作用 1.2、名词解释 1.3、简介 1.4、工作原理 1.5、应用实例 2、 VRRP配置 2.1、配置命令 2.2、拓扑与配置&#xff1a; 1、VRRP虚拟路由器冗余协议 1.1、协议作用 虚拟路由冗余协议(Virtual Router Redundancy Protocol&am…...

ubuntu操作系统的docker更换存储目录

前言 要将Docker的存储目录更改为/home/docker&#xff0c;你需要进行以下步骤&#xff1a; 目录 前言1、停止Docker服务2、创建新的存储目录3、编辑Docker配置文件4、启动Docker服务5、验证更改 1、停止Docker服务 首先停止Docker守护进程&#xff0c;可以使用以下命令&…...

【人工智能Ⅰ】6-机器学习之分类

【人工智能Ⅰ】6-机器学习之分类 6-1 机器学习在人工智能中的地位 学习能力是智能的本质 人工智能 > 机器学习 > 深度学习 什么是机器学习&#xff1f; baidu&#xff1a;多领域交叉学科&#xff08;做什么&#xff09; wiki&#xff1a;the study of algorithms and…...

本地部署_语音识别工具_Whisper

1 简介 Whisper 是 OpenAI 的语音识别系统&#xff08;几乎是最先进&#xff09;&#xff0c;它是免费的开源模型&#xff0c;可供本地部署。 2 docker https://hub.docker.com/r/onerahmet/openai-whisper-asr-webservice 3 github https://github.com/ahmetoner/whisper…...

秋招求职经验分享

0.个人简介 2023年10月底&#xff0c;最终拿到了海康威视、汇川技术等十余家公司的Offer&#xff0c;最终签了自己心仪的Offer&#xff0c;秋招对我来说算是正式结束了&#xff0c;写个博客纪念一下&#xff0c;顺便分享以下秋招的经验&#xff0c;为后来人求职提供一些参考。…...

DNS域名解析

目录 1.概述 1.1产生原因 1.2作用 1.3连接方式 1.4因特网的域名结构 1.4.1拓扑 1.4.2分类 1.4.3域名服务器类型划分 2. DNS域名解析过程 2.1分类 2.2解析图 2.2.2过程分析 3.搭建DNS域名解析服务器 3.1.概述 3.2安装软件 3.3bind服务中三个关键文件 3.4主配置…...

Flink SQL --命令行的使用(02)

1、窗口函数&#xff1a; 1、创建表&#xff1a; -- 创建kafka 表 CREATE TABLE bid (bidtime TIMESTAMP(3),price DECIMAL(10, 2) ,item STRING,WATERMARK FOR bidtime AS bidtime ) WITH (connector kafka,topic bid, -- 数据的topicproperties.bootstrap.servers m…...

【nlp】1.3 文本数据分析(标签数量分布、句子长度分布、词频统计与关键词词云)

文本数据分析 1 文本数据分析介绍2 数据集说明3 获取标签数量分布4 获取句子长度分布5 获取正负样本长度散点分布6 获取不同词汇总数统计7 获取训练集高频形容词词云8 获取验证集形容词词云1 文本数据分析介绍 文本数据分析的作用: 文本数据分析能够有效帮助我们理解数据语料…...

路由器的结构以及工作原理

目录 路由器的结构 交换结构三种常用的交换方式 1.通过存储器 2.通过总线 3.通过纵横交换结构&#xff08;crossbar switch fabric&#xff09; 路由器的结构 路由器结构可划分为两大部分&#xff1a;路由选择部分&#xff0c;分组转发部分 路由选择部分也叫做控制部分&…...

DefaultListableBeanFactory

DefaultListableBeanFactory 是一个完整的、功能成熟的 IoC 容器&#xff0c;如果你的需求很简单&#xff0c;甚至可以直接使用 DefaultListableBeanFactory&#xff0c;如果你的需求比较复杂&#xff0c;那么通过扩展 DefaultListableBeanFactory 的功能也可以达到&#xff0c…...

NSF服务器

目录 1.简介 1.1 NFS背景介绍 1.2 生产应用场景 2.NFS工作原理 2.1 实例图 2.2 流程 3.NFS的使用 3.1.安装 3.2.配置文件 3.3.主配置文件分析 3.4 实验 服务端&#xff1a; 客户端&#xff1a; 3.5.NFS账户映射 3.5.1.实验2 3.5.2.实验3 4.autofs自动挂载服务…...

10 Go的映射

概述 在上一节的内容中&#xff0c;我们介绍了Go的结构体&#xff0c;包括&#xff1a;定义结构体、声明结构体变量、使用结构体、结构体关联函数、new、组合等。在本节中&#xff0c;我们将介绍Go的映射。Go语言中的映射&#xff08;Map&#xff09;是一种无序的键值对集合&am…...

瑞萨e2studio(29)----SPI速率解析

瑞萨e2studio.29--SPI速率解析 概述视频教学时钟配置解析RA4M2的BRR值时钟速率7.5M下寄存器值3K下寄存器值 概述 在嵌入式系统的设计中&#xff0c;串行外设接口&#xff08;SPI&#xff09;的通信速率是一个关键参数&#xff0c;它直接影响到系统的性能和稳定性。瑞萨电子的…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句&#xff0c;它能够让用户直接在浏览器内练习SQL的语法&#xff0c;不需要安装任何软件。 链接如下&#xff1a; sqliteviz 注意&#xff1a; 在转写SQL语法时&#xff0c;关键字之间有一个特定的顺序&#xff0c;这个顺序会影响到…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...