数据结构第六讲:栈和队列

news2024/11/19 4:22:37

数据结构第六讲:栈和队列

  • 1.栈
    • 1.1概念与结构
    • 1.2栈的实现
      • 1.2.1栈的基础框架
      • 1.2.2栈的初始化
      • 1.2.3栈的销毁
      • 1.2.4栈的插入(压栈)
      • 1.2.5栈的删除(出栈)
      • 1.2.6获取栈顶元素
      • 1.2.7获取栈中有效数据的个数
  • 2.队列
    • 2.1概念与结构
    • 2.2队列的实现
      • 2.2.1队列的基础框架
      • 2.2.2队列的初始化
      • 2.2.3入队列
      • 2.2.4出队列
      • 2.2.5销毁队列
      • 2.2.6取队列头节点数据
      • 2.2.7取队列尾节点数据
      • 2.2.8队列中有效元素的个数

1.栈

1.1概念与结构

栈:栈是一种特殊的线性表,只允许在固定的一端进行插入和删除操作,遵循LIFO(last in first out)的原则
压栈:栈的插入操作成为压栈/入栈/进栈,插入操作在栈顶
出栈:栈的删除成为出栈,删除操作也在栈顶
在这里插入图片描述
栈可以通过使用数组或链表来实现,相对而言使用数组实现较好,因为数组实现尾插的时间复杂度为O(1)

1.2栈的实现

栈的实现过程与顺序表的实现方法非常相似,所以这里就不着重阐述了

1.2.1栈的基础框架

与顺序表不同的是,这里没有用来存储有效数据的变量,变成了一个栈顶变量,大小也是有效变量的个数

typedef int StackDataType;

typedef struct Stack
{
	StackDataType* arr;//使用一个指针来指向开辟的数组
	int capacity;//保存数组的空间大小
	int top;//指向栈顶
}Stack;

1.2.2栈的初始化

直接将变量进行初始化即可

//栈的初始化
void Init(Stack* ps)
{
	assert(ps);

	ps->arr = NULL;
	ps->capacity = ps->top = 0;
}

1.2.3栈的销毁

直接销毁即可

//栈的销毁
void Destory(Stack* ps)
{
	assert(ps);

	//注意:这个要加上if进行判断,为了确保arr数组不是指向NULL
	if(ps->arr)
		free(ps->arr);
	ps->arr = NULL;
	ps->capacity = ps->top = 0;
}

1.2.4栈的插入(压栈)

//栈的插入
void StackPush(Stack* ps, StackDataType x)
{
	assert(ps);

	//因为只有栈的插入才需要开辟空间,所以开辟结点空间不必封装成一个函数
	if (ps->top == ps->capacity)
	{
		//空间不足,需要开辟
		int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		StackDataType* parr = (StackDataType*)realloc(ps->arr, newcapacity * sizeof(StackDataType));
		if (parr == NULL)
		{
			perror("malloc faile!");
			exit(1);
		}
		ps->arr = parr;
		ps->capacity = newcapacity;
	}
	ps->arr[ps->top++] = x;
}

1.2.5栈的删除(出栈)

//栈的删除
void StackPop(Stack* ps)
{
	//栈为NULL时不能删除,栈中没有数据时不能删除
	assert(ps && ps->top);

	--ps->top;
}

1.2.6获取栈顶元素

//取栈顶元素
StackDataType StackPrint(Stack* ps)
{
	assert(ps && ps->top);

	return ps->arr[ps->top-1];
}

1.2.7获取栈中有效数据的个数

有效数据的个数就是top的大小

//获取栈中有效元素个数
int StackSize(Stack* ps)
{
	assert(ps);

	return ps->top;
}

2.队列

2.1概念与结构

队列也是一种特殊的线性表,与栈不同的是,队列只允许在一端进行插入数据操作,在另一端进行数据删除操作,遵循的是FIFO(first in first out)原则
入队列:进行插入的一端称为队尾
出队列:进行删除的一端称为队头
在这里插入图片描述
队列也可以使用数组和链表两种方法完成,但是这时链表要更好一点,因为链表的删除只需要改变指针的指向即可

2.2队列的实现

2.2.1队列的基础框架

队列的实现不同于单链表,它需要两个结构体变量

//结点结构体
typedef int QueueDataType;

typedef struct QueueNode
{
	//和链表一样,也需要结点进行链接
	QueueDataType val;
	struct QueueNode* next;
}QueueNode;

//队列结构体
typedef struct Queue
{
	QueueNode* head;//指向队列的头部,方便删除数据
	QueueNode* tail;//指向队列的尾部,方便插入数据
	int size;//用来记录有效数据的个数
}Queue;

2.2.2队列的初始化

直接进行初始化即可

//队列初始化
void Init(Queue* pq)
{
	assert(pq);

	pq->head = pq->tail = NULL;
	pq->size = 0;
}

2.2.3入队列

也就是插入队列,在队列的末尾进行插入即可

//入队列
void QueuePush(Queue* pq, QueueDataType x)
{
	assert(pq);

	//只有入队列需要开辟结点空间
	QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
	if (newnode == NULL)
	{
		perror("malloc faile!");
		exit(1);
	}
	newnode->val = x;
	newnode->next = NULL;
	//要分情况讨论:当队列一开始没有一个结点时
	if (pq->head == NULL)
	{
		pq->head = pq->tail = newnode;
	}
	else
	{
		//直接插入到末尾即可
		//head ... tail newnode
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
	pq->size++;
}

2.2.4出队列

改变头结点的指针,然后释放空间即可

//出队列
void QueuePop(Queue* pq)
{
	assert(pq && pq->head);

	//出队列要求从队列开头进行删除
	//此时要分情况讨论:当只具有一个结点时
	if (pq->head == pq->tail)
	{
		free(pq->head);
		pq->head = pq->tail == NULL;
	}
	else
	{
		//pq->head pq->head->next
		QueueNode* tmp = pq->head->next;
		free(pq->head);
		pq->head = tmp;
	}
	--pq->size;
}

2.2.5销毁队列

与链表的销毁相同,需要通过两个指针进行循环销毁

//销毁队列
void Destory(Queue* pq)
{
	assert(pq && pq->head);

	QueueNode* prev = pq->head;
	QueueNode* next = pq->head->next;
	while (prev)
	{
		free(prev);
		prev = next;
		if(next)
			next = next->next;
	}
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

2.2.6取队列头节点数据

头节点数据直接提取即可

//取队列头结点数据
QueueDataType QueueFront(Queue* pq)
{
	assert(pq && pq->head);

	return pq->head->val;
}

2.2.7取队列尾节点数据

//取队列尾节点数据
QueueDataType QueueBack(Queue* pq)
{
	assert(pq && pq->head && pq->tail);

	return pq->tail->val;
}

2.2.8队列中有效元素的个数

有效元素个数在结构中进行保存,直接提取即可

//队列有效元素的个数
int QueueSize(Queue* pq)
{
	assert(pq);

	return pq->size;
}

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

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

相关文章

PyTorch 2.0 GPU Nvidia运行库的安装

【图书推荐】《PyTorch深度学习与计算机视觉实践》-CSDN博客 假设读者电脑带有NVIDIA 20 以上系列的显卡。 我们以CUDA 11.7cuDNN 8.2.0(其他更高版本的组合,读者可以执行查阅PyTorch官网获得)为例,讲解PyTorch 2.0 GPU版本的安…

Cocos Creator2D游戏开发(4)-飞机大战(2)-编辑器界面

编辑器几个重要板块 参考: https://docs.cocos.com/creator/3.8/manual/zh/editor/ (1) 场景编辑器: 仅看2D视图: 按钮作用依次是: 平移, 旋转,缩放,矩形变换,增量吸附工具,最后三个,前俩是变换工具,最后一个是布局组件 矩形变换: 中心点和锚点切换 以后用到慢慢整吧! (2)层…

大语言模型的Scaling Law:如何随着模型大小、训练数据和计算资源的增加而扩展

人工智能的世界正在经历一场革命,大型语言模型正处于这场革命的前沿,它们似乎每天都在变得更加强大。从BERT到GPT-3再到PaLM,这些AI巨头正在推动自然语言处理可能性的边界。但你有没有想过是什么推动了它们能力的飞速提升? 在这篇…

反向代理和负载均衡

目录 步骤1 代理技术介绍 代理技术常见的类型 正向代理的用途 反向代理的作用 步骤2 反向代理配置 步骤3 负载均衡 1、路由模式(推荐) 2、桥接模式 3、服务直接返回模式 4、负载均衡算法介绍 1、轮询法 2、随机法 3、最小连接法 步骤4 nginx…

数据结构:队列(顺序存储和链式存储)

文章目录 1. 队列的概念和结构2. 队列的链式存储实现2.1 初始化2.2 判断队列是否为空2.3 入队列2.4 出队列2.5 取队头数据2.6 取队尾数据2.7 队列有效数据的个数2.8 打印队列数据2.9 销毁2.10 源代码 3. 队列的顺序存储实现(循环队列)3.1 初始化3.2 判断队列是否为空3.3 判断队…

五、获取树形结构数据递归写法

1、mysql库表字段 学习:构建表结构时的规范,字段类型的选择 CREATE TABLE pms_category (cat_id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 分类id,name char(50) DEFAULT NULL COMMENT 分类名称,parent_cid bigint(20) DEFAULT NULL COMMENT 父分类…

2024年必知:9大项目成本管理系统推荐

本文将分享9大优质项目成本管理系统:PingCode、Worktile、中望软件、用友、智慧工地云平台、SAP ERP、Microsoft Project、Wrike、Zoho Projects。 在项目管理领域,控制成本往往是最挑战的一环,特别是在预算和资源受限的情况下。选择合适的项…

从0开始搭建vue + flask 旅游景点数据分析系统(二):搭建基础框架

这一期目标是把系统的布局给搭建起来,采用一个非常简单的后端管理风格,可以参考官方的页面 https://element.eleme.cn/#/zh-CN/component/container 下面我们开始搭建,首先,安装一下vue-router,element-ui npm insta…

【前端 12】js事件绑定

JavaScript 事件绑定 在Web开发中,事件绑定是实现用户与网页交互的重要机制。JavaScript 提供了多种方式来绑定和处理事件,使得开发者能够灵活地控制网页的行为。本文将详细介绍JavaScript中事件绑定的两种主要方式,并通过实例演示如何应用这…

查找(find)磁盘分区 压缩

一:查找的应用 find 查找位置 选项 参数 按用户查找 属主是root find /root -user root 按文件类型查找 文件类型为普通文件的 find /root -type f 文件类型为目录的 find /root -type d fin…

机器学习算法——常规算法,在同的业务场景也需要使用不同的算法(一)

👨‍💻个人主页:开发者-曼亿点 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 曼亿点 原创 👨‍💻 收录于专栏&#xff1a…

渗透测试——prime1靶场实战演练{常用工具}端口转发

文章目录 概要信息搜集 概要 靶机地址:https://www.vulnhub.com/entry/prime-1,358 信息搜集 nmap 扫网段存活ip及端口 找到除了网关外的ip,开放了80端口,登上去看看 是一个网站,直接上科技扫一扫目录 python dirsearch.py -u …

YUV/NV12、ARGB8888图像同比例缩放,不拉伸处理

1)图像处理入门级程序设计,分享给将要学习或者正在学习图像开发的同学。 2)内容属于原创,若转载,请说明出处。 3)提供相关问题有偿答疑和支持。 需求:基于SigmaStar平台SSC375,实…

深入源码:解析SpotBugs (2) 检测运行流程

1. 架构概述 SpotBugs的架构设计主要围绕以下几个核心组件展开: 分析引擎:这是SpotBugs的核心,负责读取Java字节码(.class文件),并应用预定义的规则集来检测潜在的代码问题。规则集:一组预定义…

『 Linux 』线程控制

文章目录 线程库线程的创建线程库中的线程ID线程等待及线程退出C11 中的线程库线程库的线程与轻量型进程 线程库 在Linux内核中没有实际的线程概念,只有轻量级进程的概念,即使用task_struct内核数据结构模仿线程; 所以本质上在Linux内核中无法直接调用系统调用接口创建线程,只能…

人工智能学习①

LLM背景知识介绍 大语言模型 (LLM) 背景 用于理解和生成人类语言,能够处理诸如文本分类、问答、翻译和对话等多种自然语言任务。 语言模型 (Language Model, LM) :给定一个短语(一个词组或者一句话)语言模型可以生成&#xff0…

机器学习数学基础(1)--线性回归与逻辑回归

声明:本文章是根据网上资料,加上自己整理和理解而成,仅为记录自己学习的点点滴滴。可能有错误,欢迎大家指正。 1 线性回归和逻辑回归与机器学习的关系 线性回归属于机器学习 – 监督学习 – 回归 – 线性回归, 逻辑…

Apache DolphinScheduler Worker Task执行原理解析

大家好,我是蔡顺峰,是白鲸开源的高级数据工程师,同时也是Apache DolphinScheduler社区的committer和PMC member。今天我要分享的主题是《Worker Task执行原理》。 整个分享会分为三个章节: Apache DolphinScheduler的介绍Apache …

数据结构——二叉树定义

一、二叉树概念 二叉树是一种树形数据结构,其中每个节点最多有两个子节点,通常称为左子节点和右子节点。每个子节点本身又可以是一个二叉树。二叉树在计算机科学中有着广泛的应用,例如在搜索算法、排序算法等领域 二叉树(Binary Tree)是n(n…