实现栈和队列

news2025/2/24 6:37:16

文章目录

1.栈 

1.1 栈的概念及结构

1.2 栈的实现

实现栈的标识索引

数组实现栈

栈的结构定义

栈空间数据的初始化和销毁

入栈和出栈

获取栈顶元素、计算栈空间元素个数、判空

2.队列

2.1 队列的概念及结构

2.2 链表的实现 

实现链表的标识索引

链表实现队列 

定义队列的相关结构

队列的初始化和销毁 

入队、出队

入队

出队

队列判空和数据个数计算

获取队头和队尾元素

3.源码

3.1 数组实现栈

Stack.h

Stack.c

3.2 链表实现队列

Queue.h

Queue.c


顶峰相见!

  大家好,我是纪宁。这篇文章给大家介绍栈和队列,以及详细的实现个过程 。

  先导知识:顺序表(数组)单链表C语言自定义类型

1.栈 

1.1 栈的概念及结构

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

压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶

1.2 栈的实现

  栈一般可以用链表或者顺序表(数组实现),相对于链表,数组实现效率更优。

数组实现栈,尾插尾删

实现栈的标识索引

STDataType重命名后的栈内数据类型
Stack栈的结点结构
STInit栈的初始化
STpush入栈(压栈)
STPop出栈
STTop获取栈顶元素
STDestroy栈的销毁
STSize求栈元素个数
STEmpty判空(判断栈空间是否为空)

数组实现栈

  由于我们是用数组实现栈的,所以要先选择使用静态数组还是动态数组,由于静态数组的可用性较低,这里采用动态数组。

栈的结构定义

  将栈空间元素数据类型重命名为 STDataType ,这样在改变栈的数据类型后,数据结构依然可以使用;a 为栈空间的首地址,top 为栈顶位置,出栈就相当于尾删,栈顶位置前移,入栈相当于尾插。

栈空间数据的初始化和销毁

  将栈空间的指针指向初始化为 NULL,栈顶的下一个位置 top 为下标 0 ,栈空间大小初始化为 0。

  销毁栈空间,将开辟的空间释放,并让指针指向空;将栈空间的栈顶的下一个位置 top 和 占空间容量置空。

入栈和出栈

  入栈即将数据尾插在实现栈的数组后面,当栈顶的下一个位置下标 top 与栈空间大小相同时,说明栈空间已经满了,需要扩容;当第一次入栈时,栈空间本来就初始化为 0,因此第一次入栈要扩容(由0扩容到一个值,这个值可以自己定),用三目运算符来控制第一次和第N次扩容的不同:第一次扩容到固定值,第N次则扩容到原空间的 2 倍。

  需要强调的是 realloc 函数在空间大小为 0 的时候作用于 malloc 函数相同。扩容/开辟空间后,栈空间的指针指向新开辟/扩容后的地址;栈的容量大小改为扩容后的大小;top 位置的元素改为入栈元素,再将 top 后移。

  出栈的时候,要先断言栈中是否有元素你,没有元素才能出栈。

获取栈顶元素、计算栈空间元素个数、判空

  先断言,首先保证栈中有元素。由于 top 是栈顶的下一个位置的下标,那么就但会 top-1 位置的元素,就是栈顶元素。

   由于 top 是栈顶的下一个位置的下标,而下标是从 0 开始的,因此 top 的值与栈内元素的个数相等。

  当 top 等于0时,说明栈顶元素的下一个位置下标为0,那么栈中就没有元素,栈为空。 

2.队列

2.1 队列的概念及结构

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

2.2 链表的实现 

  栈可以使用数组和链表两种方式实现,但由于队列的性质是先进先出,先出要进行头删,数组头删要将所有元素移动,效率较低,所以这里采用链表实现队列。 

  用链表实现队列:入队尾插,出队头删

实现链表的标识索引

QDataType重命名后的队列元素数据类型
QueueNode队列的结点结构

Queue

结点和size的结合结构
QueueInit队列的初始化
QueueDestroy队列的销毁
QueuePush入队
QueuePop出队
QueueFront获取队头元素
QueueBack获取队尾元素
QueueEmpty队列判空
QueueSize获取队列元素个数

链表实现队列 

定义队列的相关结构

  正常定义一个单链表的结构,但由于要进行头删、尾插,定义一个指针 tail,用来指向尾结点,为了不使用二级指针,再多定义一个结构体,存储链表头指针、尾指针,顺便存储队列的元素个数。

队列的初始化和销毁 

  队列的初始化就是将队列的链表头指针和尾指针都置空,元素个数置空。由于队列是由链表定义的,所以销毁的时候要释放每次开辟的结点空间,定义一个 cur 指针来负则遍历。将所有空间都释放后,将链表头指针和尾指针置空,元素个数改为 0。

入队、出队

入队

  入队的时候,因为是链表,所以要先开辟一个结点的空间,然后改链表指向。当队列中没有数据时,要单独处理,将链表头指针和尾指针都指向新节点。

出队

  链表出队列的要判断的东西比较多。首先得判断是否有数据,还要判断是否只有一个数据,当只要一个数据的时候,释放掉空间后,tail 指针和 head 指针都要置空。当有多个数据时,只需要将头指针后移即可。

  最后,将元素个数减1。

队列判空和数据个数计算

  队列判空只需要判断头指针是否为空即可,而元素个数在每次入队或出队的时候都进行了改变,只需要返回即可。

获取队头和队尾元素

  直接返回即可,唯一要注意的就是必须保证队列里有元素,因此需要断言队列是否为空。 

3.源码

3.1 数组实现栈

Stack.h

 #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 STInit(ST* ps);
void STPush(ST* ps,STDataType x);
void STPrint(ST* ps);
void STPop(ST* ps);
void STDestroy(ST* ps);
STDataType STTop(ST* ps);
int STSize(ST* ps);
bool STEmpty(ST* ps);

Stack.c

#include "Stack.h"
void STInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}
void STPush(ST* ps, STDataType x)
{
	assert(ps);
	if (ps->capacity==ps->top)
	{
		int newcapacity = (ps->capacity == 0) ? 4 : ps->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->a, newcapacity * sizeof(ps->a));
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->capacity = newcapacity;
		ps->a = tmp;
	}
	ps->a[ps->top] = x;
	ps->top++;
}
void STPrint(ST* ps)
{
	assert(ps);
	int i = 0;
	for (i = 0; i < ps->top; i++)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}
void STPop(ST* ps)
{
	assert(ps);
	assert(ps->top>0);
	(ps->top)--;
}
void STDestroy(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->top = 0;
}
STDataType STTop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);
	return ps->a[ps->top - 1];
}
int STSize(ST* ps)
{
	assert(ps);
	return ps->top;
}
bool STEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}

3.2 链表实现队列

Queue.h

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int QDataType;
typedef struct QueueNode
{
	QDataType Data;
	struct QueueNode* next;
}QNode;
typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Que;
void QueueInit(Que* pq);
void QueueDestroy(Que* pq);
void QueuePush(Que* pq,QDataType x);
void QueuePop(Que* pq);
QDataType QueueFront(Que* pq);
QDataType QueueBack(Que* pq);
int QueueSize(Que* pq);
bool QueueEmpty(Que* pq);

Queue.c

#include "Queue.h"
void QueueInit(Que* pq)
{
	assert(pq);
	pq->head = NULL;
	pq->tail = NULL;
	pq->size = 0;
}
void QueueDestroy(Que* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->tail =pq->head= NULL;
	pq->size = 0;
}
void QueuePush(Que* pq,QDataType x)
{
	assert(pq);
	QNode* nownode = (QNode*)malloc(sizeof(QNode));
	if (nownode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	nownode->Data = x;
	nownode->next = NULL;
	if (pq->head = NULL)
	{
		pq->head = pq->tail = nownode;
	}
	else
	{
		pq->tail->next = nownode;
		pq->tail = nownode;
	}
	pq->size++;
}
void QueuePop(Que* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	if (pq->head->next==NULL)
	{
		free(pq->head);
		pq->head = pq->tail = NULL;
	}
	else
	{
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
	pq->size--;
}
QDataType QueueFront(Que* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->head->Data;
}
QDataType QueueBack(Que* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->tail->Data;
}
bool QueueEmpty(Que* pq)
{
	assert(pq);
	return pq->head == NULL;
}
int QueueSize(Que* pq)
{
	assert(pq);
	return pq->size;
}

在这里插入图片描述

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

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

相关文章

JavaScript基础 第一天

本套笔记是通过学习B站Pink老师JavaScript核心进阶 前端必学总结的学习笔记&#xff0c;希望自己之后在使用的过程中能够将所学知识融会贯通 学习目标 1. 理解变量是存储数据的容器 2.理解什么是数据并知道数据的类型 3.知道JavaScript数据类型转换的特征 学习目录 1.Jav…

java 自定义xss校验注解实现

自定义一个注解Xss。名字随意 import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Targe…

JVM垃圾回收篇-垃圾回收算法与五种引用

JVM垃圾回收篇-垃圾回收算法与五种引用 引用计数法 引用计数&#xff08;英语&#xff1a;reference counting&#xff0c;RC&#xff09;是计算机编程语言中的一种内存管理技术&#xff0c;是指将资源&#xff08;可以是对象、内存或磁盘空间等等&#xff09;的被引用次数保…

mac安装open3d时候出现错误

在测试open3d是否正常顺利安装时&#xff0c;出现了如下错误&#xff1a; python -c "import open3d as o3d; print(o3d.__version__)" Traceback (most recent call last):File "<string>", line 1, in <module>File "/Users/huangzhe/…

【产品设计】消息通知系统设计

消息通知可以将内容实时送达用户手机页面&#xff0c;但是泛滥的消息通知会引起用户的反感&#xff0c;也违背了这个设计的初衷。 消息通知可以及时地将状态、内容的更新触达到用户&#xff0c;用户则可以根据收到的消息做后续判断。但是如果没有及时将重要消息触达到用户或者滥…

Java基础入门篇——数据类型(六)

目录 一、基本数据类型 1.1整型类型变量 1.2浮点型 1.3字符型 1.4布尔型 二、引用数据类型 Java是一个强类型语言&#xff0c;Java中的数据必须明确数据类型。数据类型的作用就是约束变量存储数据的形式。例如&#xff0c;定义为int类型存储整数&#xff0c;定义为double…

【分布式流控组件 Sentinel 快速入门】——图文详解操作流程

&#x1f4a7; 分布式流控组件 S e n t i n e l 快速入门 \color{#FF1493}{分布式流控组件 Sentinel 快速入门} 分布式流控组件Sentinel快速入门&#x1f4a7; &#x1f337; 仰望天空&#xff0c;妳我亦是行人.✨ &#x1f984; 个人主页——微风撞见云的博客&#…

ThreadPoolExecutor线程池详解

ThreadPoolExecutor线程池详解 1. 背景 项目最近的迭代中使用到了ThreadPoolExecutor线程池&#xff0c;之前都只是知道怎么用&#xff0c;没有了解过线程池的底层原理&#xff0c;项目刚上线&#xff0c;有时间整理一下线程池的用法&#xff0c;学习一下线程池的底层实现与工…

Stable Diffusion - Style Editor 和 Easy Prompt Selector 提示词插件配置

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132122450 Stable Diffusion 的 Prompt 的功能&#xff0c;可以用文字来描述想要生成的图像&#xff0c;根据输入来创造出逼真的图像。Prompt 支持…

Mysql面试题(查询重复数据删除重复数据)

Create table A (id int) 注意&#xff1a;id列非自增&#xff0c;由代码产生并输入&#xff0c;但代码可能产生重复id 1.业务定义中&#xff0c;id列不允许重复&#xff0c;用什么方式保证重复的id不会被输入表中&#xff1f; 2.若已经发生数据重复&#xff0c;请写出SQL语…

【C++进阶之路】继承与多态的概念考察

文章目录 一、问答题二、概念题三、答案与解析问答题概念题 一、问答题 什么是菱形继承&#xff1f;菱形继承的问题是什么&#xff1f;什么是菱形虚拟继承&#xff1f;如何解决数据冗余和二义性的。继承和组合的区别&#xff1f;什么时候用继承&#xff1f;什么时候用组合&…

9:00开始面试,9:08就出来了,这问题问的实在是····

外包工作3年&#xff0c;今年裸辞跳槽&#xff0c;很幸运的是找到了下家&#xff0c;不过 自从加入到这家公司&#xff0c;每天不是在加班就是在加班的路上&#xff0c;薪资倒是给的不少&#xff0c;所以我也就忍了。没想到6月一纸通知&#xff0c;所有人都不许加班&#xff0…

网络防御(9)

.一、SSL工作过程是什么&#xff1f; SSL位于应用层和传输层之间&#xff0c;它能够为基于TCP等可靠连接的应用层协议提供安全性保证。SSL协议本身分为两层&#xff1a; 上层为SSL握手协议&#xff08;SSL handshake protocol&#xff09;、SSLpassword变化协议&#xff08;S…

【locust】使用locust + boomer实现对接口的压测

目录 背景 环境安装 脚本编写 master slave节点&#xff08;golang/boomer&#xff09; 问题 资料获取方法 背景 很早之前&#xff0c;考虑单机执行能力&#xff0c;使用locust做过公司短信网关的压测工作&#xff0c;后来发现了一个golang版本的locust&#xff0c;性能…

HTML

HTML 1. 块级标签 标题&#xff1a; <h1>一级标题</h1> div: <div>这是一个div标签</div> p&#xff1a; <p>这是一个p标签&#xff0c;段落标签</p> <!DOCTYPE html> <html lang"en"> <head><meta charse…

使用 ESP32 Arduino 和机器学习实现WIFI室内定位

在这个 Arduino 机器学习项目中,我们将使用附近的 WiFi 接入点来定位我们所在的位置。为了使该项目正常运行,您需要一块配备 WiFi 的板,例如 ESP8266、ESP32 或 MKR WiFI 1010。 什么是室内定位? 我们都习惯了 GPS 定位,我们的设备将使用卫星来跟踪我们在地球上的位置。GP…

SOLIDWORKS Simulation的功能到底有多强大

说到知己知彼&#xff0c;这是一个老生常谈的问题&#xff0c;对于SOLIDWORKS Simulation来说&#xff0c;很多朋友经常问我&#xff0c;我要算一个某某问题&#xff0c;SOLIDWORKS Simulation能算么&#xff1f;其实&#xff0c;这个就是一个典型的不了解SOLIDWORKS Simulatio…

虚拟世界探索:科技之下的未来可能性

随着科技的飞速发展&#xff0c;人们对于虚拟世界的憧憬和探索也日益加深。虚拟世界&#xff0c;那是一个超越现实的概念&#xff0c;一个充满想象力和创造力的领域。然而&#xff0c;虚拟世界究竟有可能实现吗&#xff1f;这是一个引人深思的问题。 虚拟世界&#xff0c;首先让…

多格式兼容,PDM系统与BOM系统格式转换

在现代制造业的产品开发过程中&#xff0c;PDM系统&#xff08;Product Data Management&#xff0c;产品数据管理&#xff09;和BOM系统&#xff08;Bill of Materials&#xff0c;物料清单管理&#xff09;是不可或缺的重要工具。PDM系统负责管理产品的图文档、规格参数等信息…

Python之多重继承

一、多重继承 Python支持多重继承&#xff0c;一个子类可以有多个“直接父类”。这样&#xff0c;就具备了“多个父类”的特点。但是由于&#xff0c;这样会被“类的整体层次”搞的异常复杂&#xff0c;尽量避免使用。 class A:def aa(self):print("aa") ​ class B…