【数据结构】栈和队列详解

⭐️ 往期相关文章

✨链接1:数据结构和算法的概念以及时间复杂度空间复杂度详解
✨链接2:【数据结构】手撕顺序表
✨链接3:【数据结构】手撕单链表
✨链接4:【数据结构】双向带头循环链表


⭐️ 栈和队列

🌠 栈

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

图:
在这里插入图片描述


🌠 栈的实现

栈的实现一般可以使用数组或链表实现,相对而言数组的结构实现更优一些,数组实现可以让下标为 0 的这一端当作栈底,另一端当作栈顶,并使用一个 top 下标记录着栈定的位置,那么当 push 元素的时候只需要 O ( 1 ) O(1) O(1) 的复杂度实现插入,删除也是一样。如果采用链表实现,每次 push 元素时需要尾插,单链表的话需要每次找尾结点,这样时间复杂度就是 O ( N ) O(N) O(N) 了,或者也可以定义一个 tail 尾结点,每次则不需要找尾,但是出栈的时候又是一个问题,因为删除 tail 尾结点还需要把 tail 往前移动一下,但是此时找不到 tail 的前一个结点,还是需要遍历找 tail 结点的前一个结点。所以如果是用链表实现栈的话,最好是链表的尾部当作栈底,链表头结点当作栈顶,这样的话链表的头插头删时间复杂度都是 O ( 1 ) O(1) O(1)我们本章主要采用数组来实现栈

栈的接口

#pragma once

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

typedef int StackType;

typedef struct Stack {
	StackType* data;	
	int top;			// 栈顶
	int capacity;		// 容量
}Stack;

// 栈的初始化
void StackInit(Stack * ps);
// 栈的销毁
void StackDestroy(Stack * ps);
// 入栈
void StackPush(Stack* ps , StackType node);
// 出栈
void StackPop(Stack* ps);
// 栈是否为空
bool StackEmpty(Stack* ps);
// 栈的大小
int StackSize(Stack* ps);
// 取栈顶元素
StackType StackTop(Stack * ps);

StackInit 实现

void StackInit(Stack* ps) {
	assert(ps);

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

StackDestroy 实现

void StackDestroy(Stack* ps) {
	assert(ps);

	free(ps->data);
	ps->data = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

StackPush 实现

void StackPush(Stack* ps , StackType node) {
	assert(ps);

	// 检查容量
	if (ps->top == ps->capacity) {
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		StackType* newData = (StackType*)realloc(ps->data , sizeof(StackType) * newCapacity);
		assert(newData);
		ps->data = newData;
		ps->capacity = newCapacity;
	}

	ps->data[ps->top] = node;
	ps->top++;
}

StackPop 实现

void StackPop(Stack* ps) {
	assert(ps);

	// 判断栈是否为空
	assert(!StackEmpty(ps));

	ps->top--;
}

StackTop 实现

StackType StackTop(Stack* ps) {
	assert(ps);

	assert(!StackEmpty(ps));

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

StackEmpty 实现

bool StackEmpty(Stack* ps) {
	assert(ps);
	// 空为真,非空返回0
	return ps->top == 0;
}

StackSize 实现

int StackSize(Stack* ps) {
	assert(ps);

	return ps->top;
}

🌠 队列

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

图:
在这里插入图片描述

🌠 队列的实现

队列和栈一样都可以使用数组和链表的结构来实现,但是如果选择数组实现队列的话,下标为 0 的一端是队头,另一端是队尾,那么插入数据的时间复杂度是 O ( 1 ) O(1) O(1)但是当从队头删除数据的时候,数组需要从后往前挪动数据,效率较低。而使用链表实现队列,单链表的头删是 O ( 1 ) O(1) O(1) 的操作,但是如果要从队尾入数据单链表需要找尾,所以我们这里可以定义两个指针 headtail 这样单链表尾插时间复杂度 O ( 1 ) O(1) O(1) 就不需要每次入队列找尾结点了。所以使用队列使用链表来实现更优。

队列的接口

#pragma once

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

typedef int QueueDataType;

// 单链表实现队列
typedef struct QueueNode {
	QueueDataType data;
	struct QueueNode* next;
}QueueNode;

typedef struct Queue {
	QueueNode* head;	// 指向队头
	QueueNode* tail;	// 指向队尾
}Queue;

// 队列的初始化
void QueueInit(Queue* q);
// 队列的销毁
void QueueDestroy(Queue* q);
// 队尾入数据
void QueuePush(Queue* q , QueueDataType x);
// 队头出数据
void QueuePop(Queue* q);
// 判断队列是否为空
bool QueueIsEmpty(Queue* q);
// 获取队头数据
QueueDataType QueueFront(Queue* q);
// 获取队尾数据
QueueDataType QueueBack(Queue* q);
// 获取队列有效元素的个数
int QueueSize(Queue* q);

QueueInit 实现

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

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

QueueDestroy 实现

void QueueDestroy(Queue* q) {
	assert(q);

	QueueNode* cur = q->head;
	while (cur) {
		QueueNode* next = cur->next;
		free(cur);
		cur = next;
	}

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

QueuePush 实现

void QueuePush(Queue* q , QueueDataType x) {
	assert(q);

	// 创建新结点
	QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));
	assert(newNode);
	newNode->data = x;
	newNode->next = NULL;

	// 没有结点的情况
	if (q->tail == NULL) {
		q->head = q->tail = newNode;
	}
	else {
		// 多个结点的情况
		q->tail->next = newNode;
		q->tail = q->tail->next;
	}
} 

QueuePop 实现

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

	// 空队列
	assert(!QueueIsEmpty(q));

	// 一个结点的情况
	if (q->head->next == NULL) {	// q->head == q->tail
		free(q->head);
		q->head = q->tail = NULL;
	}
	else {
		// 多个结点的情况
		QueueNode* next = q->head->next;
		free(q->head);
		q->head = next;
	}
}

QueueIsEmpty 实现

bool QueueIsEmpty(Queue* q) {
	assert(q);

	return q->head == NULL;
}

QueueFront 实现

QueueDataType QueueFront(Queue* q) {
	assert(q);

	// 空队列
	assert(!QueueIsEmpty(q));

	return q->head->data;	// 返回队头数据
}

QueueBack 实现

QueueDataType QueueBack(Queue* q) {
	assert(q);

	// 空队列
	assert(!QueueIsEmpty(q));

	return q->tail->data;	// 返回队尾数据
}

QueueSize 实现

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

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

	return size;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenCV对图片进行缩放处理

在下面的代码中,我会为你优化和解释这段程序: #include <opencv2/opencv.hpp>using namespace cv;int main() {// 读取源图片Mat srcImage = imread("../51_resize.jpg"

目标检测学习

目录 1、目标定位 2、特征点检测 3、目标检测 4、滑动窗口的卷积实现 5、Bounding Box 预测&#xff08;Bounding box predictions&#xff09; 6、交并化 7、非极大值抑制 8、Anchor Boxes 9、YOLO算法 1、目标定位 2、特征点检测 如何检测特征点&#xff08;以人的部…

HTML5新特性总结

新增语义化标签 新增了很多语义化标签&#xff0c;如header、footer、nav、article、section(页面中的某段文字&#xff0c;或文章中的某段文字)、aside、main 其中article标签里可以包含多个section&#xff1b; section强调的是分段或分块&#xff0c;若想将一块内容分成几…

【Vscode】解决 An SSH installation couldn‘t be found

【Vscode】解决 An SSH installation couldn‘t be found 背景描述&#xff1a;在vscode中使用ssh进行连接到时候&#xff0c;已经安装了ssh romote的plugin插件&#xff0c;但是在输入了ssh连接命令之后&#xff0c;仍然出现报错&#xff1a;an ssh installation could not be…

OpenCV 入门教程:中值滤波和双边滤波

OpenCV 入门教程&#xff1a;中值滤波和双边滤波 导语一、中值滤波二、双边滤波三、示例应用3.1 图像去噪3.2 图像平滑 总结 导语 在图像处理和计算机视觉领域&#xff0c;中值滤波和双边滤波是两种常见的滤波方法&#xff0c;用于平滑图像、去除噪声等。 OpenCV 提供了中值滤…

sap abap,forms,smartforms 导出pdf

4种方法&#xff1a; 1.安装pdf程序&#xff0c;Foxit Reader,先敲回车 自动带出&#xff0c;如下图&#xff1a; 直接打印就会弹出保存pdf文档路径&#xff0c;点保存。这种方式是最简单的&#xff0c;可 forms 和 smartforms 。 2. forms 和 smartforms 打印到spool 中&…

Maven工程开发中的继承与聚合

1. 聚合工程概念 设置一个空的maven工程&#xff0c;工程里面只有pom文件&#xff0c;另外将这个工程的打包方式设置为pom。 在聚合工程里面添加聚合工程里面管理的模块 2.聚合总结 3.继承 例如下面02工程继承上面的01工程&#xff0c;在02工程的pom文件中要配置要继承的父工…

保护你的JavaScript代码:深入了解JS混淆加密及其特点

当涉及到JavaScript代码的保护和隐藏时&#xff0c;混淆加密是一种常见的技术。它通过对代码进行转换和重组&#xff0c;使其难以理解和逆向工程。以下是JS混淆加密的几个特点以及它们各自的优缺点&#xff1a; 变量和函数名压缩&#xff1a; 特点&#xff1a;将代码中的变量和…

Hystrix熔断器

雪崩 当山坡积雪内部的内聚力抗拒不了它所受到的重力拉引时&#xff0c;积雪便向下滑动&#xff0c;引起⼤量雪体崩塌&#xff0c;人们把这种自然现象称作雪崩 微服务中&#xff0c;一个请求可能需要多个微服务接口才能实现&#xff0c;会形成复杂的调用链路 …

Holoens证书过期

1. 删除Assets\WSATestCertificate.pfx证书文件。 2. 在Player Settings的Publishing Settings下找到Certificate,选择一个有效的证书。 3. 如果没有其他有效证书,需要生成一个新的测试证书: - Windows: MakeCert.exe -r -pe -n "CNTemporary Certificate" -ss MY …

Linux--操作系统进程的状态

【Linux】进程概念 —— 进程状态_linux d状态进程_Hello_World_213的博客-CSDN博客 新建&#xff1a;字面意思&#xff0c;将你的task_struct创建出来并且还未入队列 运行&#xff1a;task_struct结构体在运行队列中排队&#xff0c;就叫做运行态 阻塞&#xff1a; 等待非C…

GPT(Generative Pre-Training)论文解读及实现(一)

1 GPT Framework 1.1 Unsupervised pre-training Given an unsupervised corpus of tokens U {u1, . . . , un}, we use a standard language modeling objective to maximize the following likelihood: 在给定语料上下文环境下&#xff0c;目标时最大化下面的语言模型&…

OpenCV 图像处理算法和技术的应用实践

OpenCV 图像处理算法和技术的应用实践 导语一、图像滤波算法二、图像分割技术三、特征提取与描述算法四、实践示例&#xff1a;图像风格转换总结 导语 图像处理算法和技术在计算机视觉和图像处理领域发挥着重要作用&#xff0c;通过对图像进行分析、增强和转换&#xff0c;可以…

实验二 常用网络命令

文章目录 实验目的实验原理1. 通过 ping 命令检测网络故障2. ipconfig 命令3. arp 命令4. tracert 命令5. netstat 命令 实验内容1. ping命令2. ipconfig命令3. arp命令 实验总结 实验目的 了解常用网络命令及其使用方法。通过网络命令了解网络状态&#xff0c;并利用网络命令…

高速入门知识02:降低串扰和维持信号完整性的布线方法

文章目录 前言一、单端走线布线1.1.带有短截线的菊花链布线1.2.没有短截线的菊花链布线1.3.星型布线1.4.蛇型布线 二、差分走线布线 前言 串扰是并行走线间不需要的信号耦合。微带线和带状线正确的布线和叠层布局能够降低串扰。 双带线布局有两个靠近的信号层&#xff0c;为降…

Hbase drop 表卡住没有响应

在实际工作中遇到过重新创建一个hbase的hive外部表&#xff0c;在 disable table_name; drop table_name 在drop table_name卡住 最后有提示报错。 建议各位查看下表有无lock的情况&#xff0c; 查看和释放hbase lock可以通过如下方式来查看 pid获取&#xff1a; 在 Ma…

Python学习笔记-基于socket基础的http服务端程序

通过HTTP协议可以进行通信可以规范化的进行网络间通信。下面技术第一个http服务器小程序。简单的记录第一个试手程序。 1.http通信的基本流程 整个流程对应四层网络架构&#xff1a;应用层、传输层、网络层、链路层。有的部分已经封装&#xff0c;不需要我们再行处理。 2.服务…

轻松玩转Python正则表达式

引言 正则表达式是一种强大的文本匹配和处理工具&#xff0c;广泛应用于各种编程语言中。在Python中&#xff0c;我们可以使用内置的re模块来处理正则表达式。本文将带您从入门到精通&#xff0c;逐步介绍Python中的正则表达式用法&#xff0c;并提供实例演示。 1. 正则表达式…

JVM理论(二)类加载子系统

类加载流程 类加载流程 类加载器子系统负责从文件系统或者网络中加载class文件,class文件的文件头有特定的文件标识(CAFEBABE是JVM识别class文件是否合法的依据)classLoader只负责文件的加载,而执行引擎决定它是否被执行加载类的信息存放在运行时数据区的方法区中,方法区还包括…

VBA代码如何切换word和excel(3)

【分享成果&#xff0c;随喜正能量】人不能因为一件好事&#xff0c;高兴一整年&#xff0c;却能因为一个创伤&#xff0c;郁郁终生。痛苦给人的刺激&#xff0c;总是远远大于快乐。成年人的烦恼&#xff0c;和谁说都不合适&#xff0c;悲喜自渡&#xff0c;他人难悟。人最强大…