【数据结构初阶】--- 栈和队列

news2025/3/1 16:24:26

栈的定义

栈:只允许在一端进行插入或删除的操作
事实上,线性表和链表都可以实现栈,但栈的特点更符合用顺序表实现

  • 顺序表的队尾相当于栈顶,对栈放入数据,相当于顺序表的下标arr[index++] = x,而栈弹出数据时,相当顺序表的下标index–,即可。
  • 相比之下链表就没有这么的符合,入栈时,链表为其创建一个结点进行尾插,出栈时,进行尾删,中间的过程稍微繁琐,并没有顺序表方便
  • 所以今天我们也是用顺序表来实现一个栈
    在这里插入图片描述
    在这里插入图片描述

栈的操作

定义

说明:
top:是指向栈顶的位置,还是栈顶的下一个位置,在初始化讨论
capacity:表示栈的容量,因为是用顺序表实现,入栈的时候也需要判断是否现有元素个数是否达到容量
arr:就是个指向数组的指针

typedef int STDataType;
typedef struct ST
{
	int top;
	int capacity;
	STDataType* arr;
}ST;

初始化

说明:
初始化的时候我并没有给数组开辟空间,那么后面入栈的时候再进行扩容
因此capacity也就是0;
top:

  1. 这里我将top初始化为0,top指向的是栈顶的下一个元素
    • 此时top指向的是下标为4的位置
    • 而栈内的元素也是4,因此,我们可以用top直接表示栈内的元素个数(优势)
    • 当栈为空时,top为0
      在这里插入图片描述
  2. top指向栈顶的位置,当栈为空的时候top为-1;
    这种方式的优势在于可以将top直接当做下标
void STInit(ST* st)
{
	assert(st != NULL);

	st->arr = NULL;
	st->capacity = 0;
	st->top = 0;//指向栈顶的下一个元素
}

入栈

说明:
因为初始化的时候没有给数组开辟空间,所以入栈的时候要考虑是给栈开辟空间还是为栈扩容

void STPush(ST* st, STDataType x)
{
	assert(st != NULL);

	if (st->capacity == st->top)
	{
		int capacity = st->capacity == 0 ? 4 : st->capacity * 2;
		STDataType* newp = (STDataType*)realloc(st->arr, sizeof(STDataType) * capacity);
		if (newp == NULL)
		{
			perror("realloc fail");
			return;
		}
		st->arr = newp;
		st->capacity = capacity;
		newp = NULL;
	}

	st->arr[st->top++] = x;

}

出栈

void STPop(ST* st)
{
	assert(st);

	if (!STEmpty(st))
	{
		st->top--;
	}
}
	

返回栈顶元素

因为这里的top表示栈顶的下一个位置,所以栈顶元素的下标是top-1

STDataType STTop(ST* st)
{
	assert(st);

	if (!STEmpty(st))
	{
		return st->arr[st->top - 1];
	}
	return -1;
}

判断栈是否为空

top为0就表示栈为空

bool STEmpty(ST* st)
{
	assert(st);

	return st->top == 0;
}

返回栈内元素个数

前面说了,top表示为栈顶元素的优点在于,top可以直接表示为元素个数

int STSize(ST* st)
{
	assert(st);

	return st->top;
}

销毁栈

void STDestory(ST* st)
{
	assert(st);

	free(st->arr);
	st->top = 0;
	st->capacity = 0;
	
}

队列

队列的定义

从队的一头插入元素,另一头弹出元素
在这里插入图片描述

用顺序表实现还是用链表

  • 队列的特点是不符合顺序表来实现的,入队相当于顺序表的尾插,出队时,顺序表将下标为0的元素移除,那么只能将后面的数据依次向前移一位,出一次队就要将整个顺序表移动一次,这样的代价是非常大的。
  • 链表就很符合这个特点,入队就相当于尾插,出队就是头插,相比之下很方便,还是链表实现比较好

队列的操作

定义

用链表实现队列,那么就需要用到链表的这个结构体
队列想要入栈,是尾插,那么总不能每次插入一次就将链表遍历一遍寻找尾结点,所以,我们需要一个指针tail去记录尾结点
队列想要出栈,是头插,当然这只是原因之一,因为有了指向头结点的指针才能找到这个链表

typedef int QDataType;
typedef struct ListNode
{
	QDataType data;
	struct ListNode* next;
}ListNode;

typedef struct Queue
{
	ListNode* head;
	ListNode* tail;
}Queue;

初始化

因为队列里还没有元素,指针都置空

void QueueInit(Queue* qu)
{
	assert(qu);

	qu->head = NULL;
	qu->tail = NULL;
}

入队

每一次入队都是先创建一个结点,在进行连接
这里要考虑队列为空的情况与不为空的情况是否可以共用一套代码

void QueuePush(Queue* qu, QDataType x)
{
	assert(qu);

	ListNode* new_node = (ListNode*)malloc(sizeof(ListNode));
	if (new_node == NULL)
	{
		perror("malloc fail");
		return;
	}
	new_node->next = NULL;
	new_node->data = x;
	if (QueueEmpty(qu))
	{
		qu->head = new_node;
		qu->tail = new_node;
	}
	else
	{
		qu->tail->next = new_node;
		qu->tail = qu->tail->next;
	}
}

出队

先考虑队列为空的情况,
接着是不为空,不为空又分为一个结点和多个节点
分别去处理三种情况,尤其是要考虑只有一个结点的情况

void QueuePop(Queue* qu)
{
	assert(qu);

	if (!QueueEmpty(qu))
	{
		ListNode* tmp = qu->head;
		if (qu->head == qu->tail)//这个条件说明只有一个结点
		{
			free(tmp);
			tmp = NULL;
			qu->head = NULL;
			qu->tail = NULL;
		}
		else
		{
			qu->head = qu->head->next;
			free(tmp);
			tmp = NULL;
		}
	}
}

返回队头元素

不为空就返回head指向结点的数据,为空返回-1

QDataType QueueTop(Queue* qu)
{
	assert(qu);

	if (!QueueEmpty(qu))
	{
		return qu->head->data;
	}
	return -1;
}

返回队尾元素

QDataType QueueBack(Queue* qu)
{
	assert(qu);

	if (!QueueEmpty(qu))
	{
		return qu->tail->data;
	}
	return -1;
}

判断队列是否为空

判断是否为空很简单,只用判断两个指针是否同时为空
但也要考虑到意外状况,如果在函数外传参传错,导致两个指针其中一个为空,一个不为空,这种情况检查起来非常麻烦,所以在这里断言一下

bool QueueEmpty(Queue* qu)
{
	assert(qu);
	assert(!(qu->head == NULL && qu->tail != NULL));
	assert(!(qu->head != NULL && qu->tail == NULL));

   return qu->head == NULL && qu->tail == NULL;
}

返回队列元素个数

int QueueSize(Queue* qu)
{
	assert(qu);

	int size = 0;
	ListNode* cur = qu->head;
	while (cur != NULL)
	{
		size++;
		cur = cur->next;
	}

	return size;
}

销毁队列

相当于销毁一个链表,最后函数结束时,手动将实参qu置空

void QueueDestory(Queue* qu)
{
	assert(qu);

	ListNode* cur = qu->head;
	while (cur != NULL)
	{
		ListNode* nxt = cur->next;
		free(cur);
		cur = nxt;
	}
	qu->head = NULL;
	qu->tail = NULL;
}

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

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

相关文章

老爷机带不动影视后期?云桌面了解一下

从黑白到彩色,从默片到有声,从2D到3D,影视工业经过百余年的演变,每一步技术的提升都试图让影视艺术更接近“真实”。电影特效技术的诞生,更是为影视作品的真实感实现了一次巨大的飞跃。 但有一部分影视人,…

毕业年薪30W起!25届最近5年浙江大学自动化考研院校分析

浙江大学 目录 一、学校学院专业简介 二、考试科目指定教材 三、近5年考研分数情况 四、近5年招生录取情况 五、最新一年分数段图表 六、历年真题PDF 七、初试大纲复试大纲 八、学费&奖学金&就业方向 一、学校学院专业简介 二、考试科目指定教材 1、考试科目…

流程与IT双驱动:锐捷网络如何构建持续领先的服务竞争力?

AI大模型及相关应用进入“竞赛时代”,算力作为关键要素备受关注,由于算力行业对网络设备和性能有较大需求,其发展也在推动ICT解决方案提供商加速升级,提升服务响应速度和服务质量。 锐捷网络是行业领先的ICT基础设施及行业解决方…

黄河流域web

1、UNSER的 <?php highlight_file(__FILE__); class Wel {public $fast;public $star;public function __construct(){$this->fast "free_toto";echo "what?";}public function __destruct(){$content $this->star;printf ($content);}pu…

Prometheus写入influxDB:中间件remote_storage_adapter

Prometheus写入influxDB&#xff1a;中间件remote_storage_adapter prometheus默认采用的是本地磁盘做数据存储&#xff0c;本地存储的优势就是运维简单但是缺点就是无法海量的metrics持久化和数据存在丢失的风险,数据写入可能造成wal文件损坏导致采集数据无法再写入的问题。 …

5.4.Python 装饰器与语法糖

1. 装饰器 1.1 装饰器简介 装饰器的作用: 对函数进行装饰, 添加新的功能. 装饰器的原则: 开发封闭原则, 对扩展开放, 对修改封闭. 封闭: 已现实的功能代码块不应该被修改. 开放: 对现有功能的拓展开放. 在不改变被装饰对象内部代码以及调用方式的基础上为函数添加新的功能.1.…

Java课程设计:基于swing的学生信息管理系统

文章目录 一、项目介绍二、项目展示三、源码展示四、源码获取 一、项目介绍 这款Java swing实现的学生信息管理系统和jsp版本的功能很相似&#xff0c;简单的实现了班级信息的增删改查&#xff0c;学生信息的增删改查&#xff0c;数据库采用的是mysql&#xff0c;jdk版本不限&…

fuel无人机自主探索代码解读3——fast_exploration_fsm.cpp【状态机】

一、概述 fast_exploration_fsm.cpp订阅实时定位和目标点信息&#xff0c;每隔0.01s执行一次状态机&#xff0c;进行状态切换&#xff1b;每隔0.05s执行一次碰撞检测&#xff0c;按需进行重新规划&#xff1b;每0.5s执行一次边界回调定时器&#xff0c;对于处于WAIT_TRIGGER和…

nacos注册中心配置中心

文章目录 1.Nacos安装与简单使用1.1. Nacos安装指南Windows安装下载安装包解压端口配置启动访问 Linux安装安装JDK上传安装包解压端口配置启动 1.2.服务注册到nacos使用步骤引入依赖配置nacos地址重启 示例父工程pom.xmluser-servicepom.xmlapplication.ymlUserApplicationUser…

杨校老师项目之基于SpringBoot的理发店的预约管理系统

原系统是SSMJSP页面构成&#xff0c;先被修改为SpringBoot JSP页面 自助下载渠道: https://download.csdn.net/download/kese7952/89417001&#xff0c;或 点我下载 理发师信息&#xff1a; 理发师详细信息 公告信息 员工登录&#xff1a; 管理员登录

Python的网络请求

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 在上一节中多次提到了URL地址与下载网页&#xff0c;这两项是网络爬虫必备而又关键的功能&#xff0c;说到这两个功能必然会提到HTTP。本节将介绍在P…

关于投标中的合理均价基准差径靶心法(KIMI回答)

投标中的合理靶心法到底是什么呢&#xff1f;用了KIMI来进行回答&#xff1a;

python-jenkins调用流水线设置“丢弃旧的构建”(discard old builds)

背景 Jenkins任务执行&#xff0c;随之构建次数增多&#xff0c;构建日志所占磁盘大小不断增大&#xff0c;需要配置清除策略。 而 discard old builds 就是配置丢弃旧的构建&#xff1b;若是我们使用python-jenkins 调用修改配置该如何设置&#xff1f; 调用设置 这里是按…

液晶拼接屏企业应该采取哪些措施来提升整体竞争力和市场地位呢?

步入智能科技时代以来&#xff0c;商显行业面对着各式各样的挑战&#xff0c;人工智能、AI大模型等整合中&#xff0c;液晶拼接屏企业应该采取哪些措施以提升整体竞争力和市场地位。下面小编个人观点简单说一下&#xff1b;下是一些关键的措施&#xff1a; 首先&#xff0c;加…

web端即时通信技术

web端即时通信技术 对于IM/消息推送这类即时通讯系统而言&#xff0c;系统的关键就是“实时通信”能力。所谓实时通信有以下两层含义 客户端可以主动向服务端发送信息。 当服务端内容发生变化时&#xff0c;服务端可以实时通知客户端。 HTTP局限 Http是客户端/服务器模式中…

Linux文件系统讲解!

一、Linux文件系统历史 1、在早期的时候Linux各种不同发行版拥有自己各自自定义的文件系统层级结构。 2、当我用Red hat转向玩Debian时&#xff0c;我进入/etc我都是懵的。 3、后来Linux社区做了一个标准、FHS&#xff08;文件系统标准层次结构&#xff09;。来帮助Linux系统的…

Android 13 高通设备热点低功耗模式(2)

前言 之前写过一篇文章:高通热点被IOS设备识别为低数据模式,该功能仿照小米的低数据模式写的,散发的热点可以达到被IOS和小米设备识别为低数据模式。但是发现IOS设备如果后台无任何网络请求的时候,息屏的状态下过一会,会自动断开热点的连接。 分析 抓取设备的热点相关的…

windows下编译linux的go程序报错gcc_linux_amd64.c: In function ‘_cgo_sys_thread_start‘:

报错解决 执行报错 报错解决 其他补充 windows下编译linux 64位程序 set GOARCHamd64 set GOOSlinux set CGO_ENABLED0 go build手把手教你实现Golang跨平台编译 报错解决其他补充windows下编译linux 64位程序Windows下编译Mac平台64位可执行程序&#xff1a;Linux 下编译…

NewspaceAi之GPT使用新体验

GPT功能 使用地址&#xff1a;https://newspace.ai0.cn/ 上车 挂挡 踩油门&#xff0c;一脚到底&#xff0c;开始你的表演 问题1&#xff1a;你能做什么详细告诉我&#xff1f; 下面内容是GPT的回答 当然&#xff01;作为一个基于GPT-4架构的AI&#xff0c;我能够在许多方面为…

成功在服务器liunx-ubantu上安装pytorch

sudo pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118参考链接&#xff1a; 教程&#xff08;部分参考&#xff09; Pytorch官网