数据结构之栈与队列详解

news2024/11/15 20:31:03

文章目录

  • 前言
  • 一、栈
    • 1.栈的概念及定义
    • 2.栈的实现
      • (1)栈的结构
      • (2)StackInit(初始化)
      • (3)StackPush(压栈)
      • (4)StackPop(出栈)
      • (5)StackTop(取栈顶的元素)
      • (6)StackEmpty(检查栈是否为空)
      • (7)StackDestroy(销毁栈)
    • 3.完整代码
      • (1)头文件
      • (2)源文件
  • 二、队列
    • 1.队列的概念及定义
    • 2.队列的实现
      • (1)队列的结构
      • (2)QueueInit(初始化)
      • (3)QueuePush(入队)
      • (4)QueuePop(出队)
      • (5)QueueFront(获取头部元素)
      • (6)QueueBack(获取尾部元素)
      • (7)QueueEmpty(检查队列是否为空)
    • 3.完整代码
      • (1)头文件
      • (2)源文件
  • 结语


前言

在这里插入图片描述


栈和队列是一种特殊的线性结构,他与之前学的线性结构不同,栈和队列是拥有一种特殊规则的线性结构,虽然它是用数组或者链表实现,但是只有符合这种规则才能被称作栈或者队列

一、栈

1.栈的概念及定义

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。

在这里插入图片描述

2.栈的实现

栈的实现有两种实现,但是我们可以想想栈的特点,后进先出,我们只对尾部操作,那么是不是用数组刚好合适,虽然用链表也可以,但是数组的尾插的损耗更加小一点,所以我这里就一数组来进行讲解

在这里插入图片描述
我这里用动态的数组来实现栈

(1)栈的结构

typedef int STDataType;//方便存储各种数据
typedef struct Stack
{
	STDataType* a;
	int top;//栈顶位置,如果等于capacity=0时为空
	int capacity;//容量
}ST;

(2)StackInit(初始化)

void StackInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->top = 0;//初始化时如果top是0,即top指向栈顶上的后一位,所以取出元素时需要减一
	ps->capacity = 0;
}

(3)StackPush(压栈)

void StackPush(ST* ps, STDataType x)
{
		assert(ps);
		if (ps->top == ps->capacity)
		{
			int newcapacity = ps->capacity == 0 ? 4: ps->capacity * 2;
			STDataType* temp = (STDataType * )realloc(ps->a, sizeof(STDataType)*newcapacity);
			if (temp == NULL)
			{
				printf("realloc fail\n");
				exit(-1);
			}
			ps->a = temp;
			ps->capacity = newcapacity;
		}
		ps->a[ps->top] = x;
		ps->top++;

}

这里的代码参考动态数组的实现

(4)StackPop(出栈)

void StackPop(ST* ps) 
{
	assert(ps);
	assert(ps->top > 0);
	ps->top--;
}

(5)StackTop(取栈顶的元素)

STDataType StackTop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);
	return ps->a[ps->top - 1];//这里需要减一是因为top指向栈顶上的后一位,如果还不理解就看初始化代码
}

(6)StackEmpty(检查栈是否为空)

布尔类型的数据在c使用需要加stdbool头文件

bool StackEmpty(ST* ps)
{
	return ps->top == 0;
}

(7)StackDestroy(销毁栈)

void StackDestroy(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

3.完整代码

(1)头文件

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;
void StackInit(ST* ps);
void StackDestroy(ST* ps);
void StackPush(ST* ps,STDataType x);
void StackPop(ST* ps);
STDataType StackTop(ST* ps);
bool StackEmpty(ST* ps);
 

(2)源文件

#include"Stack.h"
void StackInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->top = 0;//初始化时如果top是0,即top指向栈顶上的后一位
	ps->capacity = 0;
}
void StackDestroy(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;

}
void StackPush(ST* ps, STDataType x)
{
		assert(ps);
		if (ps->top == ps->capacity)
		{
			int newcapacity = ps->capacity == 0 ? 4: ps->capacity * 2;
			STDataType* temp = (STDataType * )realloc(ps->a, sizeof(STDataType)*newcapacity);
			if (temp == NULL)
			{
				printf("realloc fail\n");
				exit(-1);
			}
			ps->a = temp;
			ps->capacity = newcapacity;
		}
		ps->a[ps->top] = x;
		ps->top++;

}
void StackPop(ST* ps) 
{
	assert(ps);
	assert(ps->top > 0);
	ps->top--;
}
STDataType StackTop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);
	return ps->a[ps->top - 1];
}
bool StackEmpty(ST* ps)
{
	return ps->top == 0;
}

至此,栈算是搞完了,接下来讲队列

二、队列

1.队列的概念及定义

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头

在这里插入图片描述

2.队列的实现

在这里插入图片描述

队列需要能够对头和尾操作,所以数组是不好实现的,我们用链表来实现

(1)队列的结构

队列的特点与排队购物差不多,我们要能够控制头的出和尾的进,所以与栈不一样,我们需要头和尾的位置所以我们就要实现成下面的样子

typedef int QDataType;
typedef struct QueueNode//队列的节点
{
	struct QueueNode* next;
	QDataType data;
}QN;
typedef struct Queue//存储了头和尾,方便我们直接对头和尾操作
{
	QN* head;
	QN* tail;
}Queue;

此处的实现可以参考我前面的文章链表

(2)QueueInit(初始化)

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = NULL;
	pq->tail = NULL;
}

(3)QueuePush(入队)

尾入

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QN* newnode = (QN*)malloc(sizeof(QN));
	newnode->data = x;
	newnode->next = NULL;
	if (pq->head == NULL)
	{
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}

}

(4)QueuePop(出队)

头出

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	QN* next = pq->head->next;
	free(pq->head);
	pq->head = next;
	if (pq->head == NULL)
	{
		pq->tail = NULL;
	}
}

(5)QueueFront(获取头部元素)

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->head->data;
}

(6)QueueBack(获取尾部元素)

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq->tail));
	return pq->tail->data;
}

(7)QueueEmpty(检查队列是否为空)

布尔类型需要包括头文件stdbool

bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->head == NULL;
}

3.完整代码

(1)头文件

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QN;
typedef struct Queue
{
	QN* head;
	QN* tail;
}Queue;

void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);
void QueuePush(Queue* pq, QDataType x);
void QueuePop(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
int QueueSize(Queue* pq);
bool QueueEmpty(Queue* pq);

(2)源文件

#include"Queue.h"
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = NULL;
	pq->tail = NULL;
}
void QueueDestroy(Queue* pq)
{
	assert(pq);
	QN* cur = pq->head;
	while (cur)
	{
		QN* next = cur->next;
		free(cur);
		cur = next;
	}
}
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QN* newnode = (QN*)malloc(sizeof(QN));
	newnode->data = x;
	newnode->next = NULL;
	if (pq->head == NULL)
	{
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}

}
void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	QN* next = pq->head->next;
	free(pq->head);
	pq->head = next;
	if (pq->head == NULL)
	{
		pq->tail = NULL;
	}
}
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->head->data;
}
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq->tail));
	return pq->tail->data;
}

bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->head == NULL;
}

结语

好了,栈和队列算是讲完了,如果有什么不妥之处欢迎指正,谢谢

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

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

相关文章

与众不同的异域年夜饭体验,你最中意哪一款?

年夜饭&#xff0c;中国人一年中最重要的一顿团圆聚餐&#xff0c;不仅丰富多彩&#xff0c;还充满了各种吉祥寓意。如果你选择的是出境旅游过春节&#xff0c;那么一次异域年夜饭体验也可以让你的旅行充满乐趣&#xff0c;收获与众不同的别样回忆。今天就跟着小旅城去看看&…

1597_AURIX_TC275_GPIO简介

全部学习汇总&#xff1a; GreyZhang/g_TC275: happy hacking for TC275! (github.com) 左上角画出来的这个寄存器可以进行输入输出的控制。从右边上下拉设备这里可以看得出来&#xff0c;输入输出其实都是可以配置的。当端口配置为输入的时候&#xff0c;逻辑图中的输出驱动会…

使用文本编辑器编写Java源代码

使用文本编辑器编写Java源代码 编写JavaJavaJava应用程序&#xff0c;可以使用任何一个文本编辑器来编写程序的源代码&#xff0c;然后使用JDKJDKJDK搭配的工具进行编译和运行&#xff0c;在这里&#xff0c;我将介绍一个使用简单的文本编辑器来开发一个JavaJavaJava应用程序的…

【创业分享】2022年,仅赚几万,但却很踏实?

大家好&#xff0c;欢迎来到停止重构的频道。本期&#xff0c;我们停一下技术讨论&#xff0c;反思一下2022年的变化以及展望一下2023年。回顾2022这是我们以正式商业主体创业的第一年。总的来说&#xff0c;除了不赚钱和软件产品还没做出来以外&#xff0c;其实还不错。自媒体…

Linux常用命令——tcpreplay命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) tcpreplay 将PCAP包重新发送&#xff0c;用于性能或者功能测试 补充说明 简单的说&#xff0c;tcpreplay是一种pcap包的重放工具&#xff0c;它可以将用ethreal、wireshark工具抓下来的包原样或经过任意修改后…

Spark Core 编程入门,常用算子介绍

RDD的创建 如下代码&#xff0c;Spark RDD编程的入口对象是SparkContext对象(不论何种编程语言)&#xff0c;只有构建出SparkContext&#xff0c;基于它才能执行后续的API调用和计算 本质上&#xff0c;Spark Context对编程来说&#xff0c;主要功能就是创建第一个RDD出来 # …

JVM 垃圾回收(深入理解Java虚拟机第三章)

垃圾判断算法 引用计数法 每个对象增加引用计数器&#xff0c;引用加一&#xff0c;失效减一&#xff0c;为零判定为垃圾数据。 缺点&#xff1a;循环引用难以解决 根搜索算法 从树状引用链向下查找&#xff0c;如果对象无法找到&#xff0c;则标记为垃圾数据。 JVM算法 …

Java反射学习

反射的概念 Reflection(反射&#xff09;是Java被视为动态语言的关键 反射机制允许程序在执行期借助于Reflection API获得任何类的内部信息&#xff0c; 并能直接操作任意对象的内部属性及方法。 加载完类之后&#xff0c;在堆内存的方法区中就产生了一个Class类型的对象&…

【JavaEE】阻塞队列 + 生产者消费者模型

目录 阻塞队列 阻塞队列的使用 生产者消费者模型 模型的两个好处 1. 降低耦合 2. 削峰填谷 简单实现阻塞队列 阻塞队列 阻塞队列是在一般的队列上升级而来的。 对于队列为空时&#xff0c;如果还想取队列中的元素&#xff0c;此时阻塞队列就会进行阻塞。 对于队列为满时…

fpga的SD卡读BMP图片显示实验(SPI模式)

对于 SD 卡的 SPI 模式而言&#xff0c;采用的 SPI 的通信模式为模式 3&#xff0c;即 CPOL1&#xff0c;CPHA1&#xff0c;在 SD 卡 2.0 版本协议中&#xff0c;SPI_CLK 时钟频率可达 50Mhz。SD 卡的 SPI 模式&#xff0c;只用到了 SDIO_D3&#xff08;SPI_CS&#xff09;、SD…

Nacos 部署简单使用

文章目录1、前置相关知识及说明2、官网3、环境4、Nacos 和 Zookeeper、Eureka 的主要区别5、安装部署 & 启动5.1、Windows下载安装包部署单机部署集群部署测试6、使用服务端客户端 - SpringBoot 使用 Nacos Client7、运维健康检查获取配置&#xff0c;验证服务端是否正常异…

【DX-BT24蓝牙模块连接Arduino与手机透传教程】

【DX-BT24蓝牙模块连接Arduino与手机透传教程】1. 前言2. 接线3. 程序设计详解4. 演示效果5. 小结1. 前言 大夏龙雀科技DX-BT24&BT24-S&BT24-PA蓝牙模块,拥有5.1蓝牙协议,模块内置标准串口协议。前期设置蓝牙名称为VOR&#xff0c;采用默认波特率9600&#xff0c;详细…

JavaScript 入门基础 - 对象(五)

JavaScript 入门基础 - 对象 文章目录JavaScript 入门基础 - 对象1. 对象1.1 对象的基本理解1.2 为什么需要变量2. 创建对象的方式2.1 利用字面量创建对象2.2 变量属性函数方法的区别2.3 利用 new Object 创建对象2.4 利用构造函数创建对象3.new关键字4. 遍历对象属性5. JavaSc…

二、Promise

Promise1、回调地狱1.1 如何解决回调地狱的问题1.2 Promise 的基本概念2、基于回调函数按顺序读取文件内容3. 基于 then-fs 读取文件内容3.1 then-fs 的基本使用3.2 .then() 方法的特性3.3 基于 Promise 按顺序读取文件的内容3.4 通过 .catch 捕获错误3.4 通过 .catch 捕获错误…

基于RBAC权限控制模型的管理系统的设计与实现

文章目录一、RBAC 权限设计1.1 模型概述1.2 模型分类二、基于RBAC的后台管理系统2.1 项目概述2.2 技术选型2.3 内部处理流程2.4 功能模块展示2.5 权限控制展示2.6 下载说明一、RBAC 权限设计 1.1 模型概述 基于角色的访问控制 RBAC&#xff0c;是实施面向企业安全策略的一种有…

kafka的介绍和基本使用

文章目录Kafka介绍1.Kafka的使用场景2.Kafka基本概念kafka基本使用1.安装前的环境准备2.启动kafka服务器3.创建主题topic4.发送消息5.消费消息Kafka介绍 Kafka是最初由Linkedin公司开发&#xff0c;是一个分布式、支持分区的&#xff08;partition&#xff09;、多副本的 &…

载波相位误差对BPSK解调性能的影响理论推导

在上一篇博客基础上,继续讨论载波相位误差对解调性能的影响! 【通信原理】通信原理书中解调器输入端信噪比a2/(2σ2)与比特信噪比Eb/No有什么关系? 以BPSK为例,从解调原理图可以看出,当本地参考载波信号与原始载波存在相位误差时,假设相位差为 φ \varphi φ,则解调器低…

【Linux】了解磁盘/文件系统/inode

文章目录一.磁盘1.磁盘的结构2.磁盘的定位&#xff08;寻找方案&#xff09;3.磁盘的分区与格式化介绍二.理解inode三.ext2文件系统的存储方案一.磁盘 1.磁盘的结构 问题1&#xff1a;什么是磁盘&#xff1f; 磁盘是在冯诺依曼体系结构中几乎唯一的机械设备&#xff0c;机械设…

AntDB数据库助力中国移动结算中心建设

为响应中国移动集团公司IT集中化的要求&#xff1a;全面落实“十三五”十大战略工程&#xff0c;加快“推动公司IT资源一体化整合“重点专项工作。以IT系统为载体&#xff0c;构建高效运营支撑体系&#xff0c;形成集中化支撑和协同业务支撑模式&#xff0c;打造极致体验、高效…

列表初始化(内置类型、自定义类型)

列表初始化的特性来源于单参数的隐式类型转换。以下面这个赋值为例&#xff0c;我们可以理解成 先创建一个匿名对象Point(2)&#xff0c;这个时候就变成了 Point p Point(2);然后会调用拷贝构造。 虽然隐式转换的可以这样理解&#xff0c;但是最后会被编译器优化成直接调用有…