栈及其实现

news2025/1/17 21:43:42

目录

一:栈

1.栈的概念和结构

2.栈的实现

 <1>.初始化栈

<2>.入栈

<3>.出栈

<4>:获取栈顶元素 

 <5>.获取栈中有效元素个数

<6>.销毁栈

<7>.示例

二:栈的完整代码


一:栈

1.栈的概念和结构


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

出栈:栈的删除操作叫做出栈。出数据也在栈顶。


2.栈的实现


在实现栈的时候,可以通过建立数组和链表中选择:

 在此处我们选择实现数组栈


//定义结构体,以及栈内的数据类型

// 支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{
    STDataType* _a; //数组形式
    int _top;        // 栈顶
    int _capacity;  // 容量 
}Stack;

 <1>.初始化栈


void StackInit(Stack* ps);


在初始化栈时,可以令数组为空,也可以为数组开辟一定的空间。

ps->_top = 0; 表示指向栈顶的下一个元素

ps->_pos = -1; 表示指向栈顶元素。

 代码为:

// 初始化栈 
void StackInit(Stack* ps)
{
	assert(ps);
	ps->_a = NULL;
	ps->_top = 0;//指向栈顶的下一个元素

	//ps->_top = -1;//指向栈顶的元素

	ps->_capacity = 0;
}

<2>.入栈


void StackPush(Stack* ps, STDataType data);

//画图分析得:

 


在数据入栈时会存在空间不够需要扩容的情况,在初始化时,我们的数组为NULL,并没有为其分配空间,需要先给数组一个新的容量(newcapacity),

//条件操作符

//exp1 ? exp2 : exp3

int newcapacity = ps->_capacity == 0 ? 4 : ps->_capacity * 2;

//上述代码即:若ps->_capacity == 0 , 则给其一个4字节的空间,若不为0,则给其原容量的二倍。

在给数组一个适当的容量后,需要判断所给容是否够用,即需要使用realloc来调整数组的大小

插入的数据类型为 STDataType 

//realloc
//void *realloc( void *memblock, size_t size );
//              要调整的内存地址 调整之后新的大小

STDataType* tmp = (STDataType*)realloc(ps->_a, newcapacity * sizeof(STDataType));
        if (tmp == NULL)
        {
            perror("malloc fail");
            return;
        }
        //开辟成功
        ps->_a = tmp;// 将 tmp 的空间赋给ps->_a
        ps->_capacity = newcapacity;//数组的容量为新的容量

 然后将数据插入到数组中

ps->_a[ps->_top] = data;//将数据插入

//入栈,栈顶会发生变化

ps->_top++;

代码为:

// 入栈 
void StackPush(Stack* ps, STDataType data)
{
	//入栈时,会存在空间不够需要扩容
	if (ps->_top == ps->_capacity)
	{
		//条件操作符
		//exp1 ? exp2 : exp3
		//newcapacity 等于 如果ps->_capacity 为0,则给其一个4字节空间,若不为0,给其原容量的二倍
		int newcapacity = ps->_capacity == 0 ? 4 : ps->_capacity * 2;
		//realloc
		//void *realloc( void *memblock, size_t size );
		//              要调整的内存地址 调整之后新的大小
		STDataType* tmp = (STDataType*)realloc(ps->_a, newcapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("malloc fail");
			return;
		}
		//开辟成功
		ps->_a = tmp;
		ps->_capacity = newcapacity;
	}
	ps->_a[ps->_top] = data;//将数据插入
	ps->_top++;
}

<3>.出栈


void StackPop(Stack* ps);

//画图 分析得:


 在入栈时,需要考虑栈内是否为空,在出栈时同样需要考虑,若栈内为空,则无法进行出栈操作,可以使用一个函数,来检测栈是否为空。

检测栈是否为空:


int StackEmpty(Stack* ps);

检测栈为空可以通过判断栈顶元素,在初始化时,我们可以知道ps->_top指向的是栈顶的下一个元素,若 ps->_top == 0 ; 则栈为空,即栈内没有任何元素。 

代码为:

// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps)
{
    assert(ps);
    //ps->_top --- 栈顶元素,即若 ps->_top 为0 ,则栈为空
    return ps->_top == 0;
}


检测完栈是否为空后,可以直接对 ps->_top 进行 -- 操作(因为此处采用的数组栈,当不想要最后一个元素时,可以直接 -- 。)

代码为:

// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps)
{
	assert(ps);
	//ps->_top --- 栈顶元素,即若 ps->_top 为0 ,则栈为空
	return ps->_top == 0;
}

// 出栈 
void StackPop(Stack* ps)
{
	assert(ps);
	//若栈内为空,则无法出栈,需要判断栈内是否为空。
	assert(!StackEmpty(ps));
	//断言为真则继续
	ps->_top--;
}

<4>:获取栈顶元素 

获取栈顶元素的前提是,栈内有元素,若次此栈为空栈,则无栈顶元素 --- 即在此处仍需要检测栈是否为空(函数:int StackEmpty(Stack* ps);

在初始化时,ps->_top 指向的栈顶的下一个元素,在获取栈顶元素时,可以使用 ps->_top-1.

代码为:

// 获取栈顶元素 
STDataType StackTop(Stack* ps)
{
	assert(ps);
	//栈顶元素存在 --- 栈不为空
	assert(!StackEmpty(ps));
	//ps->_top 指向的是栈顶的下一个元素
	return ps->_a[ps->_top - 1];
}

 <5>.获取栈中有效元素个数

在入栈时,我们进行了 ps->_top++ 操作

在出栈时,我们进行了 ps->_top-- 操作

初始化时,ps->_top 指向的是栈顶下一个元素

即:ps->_top 的值 等价于栈内的有效元素 (capacity 时容量,并非有效个数)

代码为:

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

	//栈内有效元素元素个数 --- 在入栈操作中,每进入一个 ps->_top++ 
	//                         在出栈操作中,每出去一个 ps->_top--; 
	//               所以  --- ps->_top 等价于站内有效元素
	return ps->_top;
}

<6>.销毁栈

我们建立的是数组栈,其空间是由 malloc 开辟来的,需要使用 free 释放,又因为是数组,所以只需要释放数组首元素。

然后将数组置为NULL,容量和栈顶都置为 0 。

代码为:

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

	free(ps->_a);//数组是由 malloc 开辟而来的,需要使用 free 释放
	ps->_a = NULL;
	ps->_capacity = 0;
	ps->_top = 0;
}

<7>.示例

代码为:

#include"stack.h"

void teat()
{
	Stack st;
	StackInit(&st);
	StackPush(&st, 1);
	StackPush(&st, 2);

	printf("%d\n", StackTop(&st));

	StackPush(&st, 3);
	StackPush(&st, 4);
	StackPush(&st, 5);

	while (!StackEmpty(&st))
	{
		printf("%d ", StackTop(&st));
		StackPop(&st);
	}

	StackDestroy(&st);


}
int main()
{
	teat();
	return 0;
}

运行结果为:

二:栈的完整代码

 Stack.h

#pragma once

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

// 支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{
	STDataType* _a; //数组形式
	int _top;		// 栈顶
	int _capacity;  // 容量 
}Stack;
// 初始化栈 
void StackInit(Stack* ps);
// 入栈 
void StackPush(Stack* ps, STDataType data);
// 出栈 
void StackPop(Stack* ps);
// 获取栈顶元素 
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数 
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
int StackEmpty(Stack* ps);
// 销毁栈 
void StackDestroy(Stack* ps);

 Stack.c

#include"stack.h"

// 初始化栈 
void StackInit(Stack* ps)
{
	assert(ps);
	ps->_a = NULL;
	ps->_top = 0;//指向栈顶的下一个元素

	//ps->_top = -1;//指向栈顶的元素

	ps->_capacity = 0;
}

// 入栈 
void StackPush(Stack* ps, STDataType data)
{
	//入栈时,会存在空间不够需要扩容
	if (ps->_top == ps->_capacity)
	{
		//条件操作符
		//exp1 ? exp2 : exp3
		//newcapacity 等于 如果ps->_capacity 为0,则给其一个4字节空间,若不为0,给其原容量的二倍
		int newcapacity = ps->_capacity == 0 ? 4 : ps->_capacity * 2;
		//realloc
		//void *realloc( void *memblock, size_t size );
		//              要调整的内存地址 调整之后新的大小
		STDataType* tmp = (STDataType*)realloc(ps->_a, newcapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("malloc fail");
			return;
		}
		//开辟成功
		ps->_a = tmp;
		ps->_capacity = newcapacity;
	}
	ps->_a[ps->_top] = data;//将数据插入
	ps->_top++;
}

// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps)
{
	assert(ps);
	//ps->_top --- 栈顶元素,即若 ps->_top 为0 ,则栈为空
	return ps->_top == 0;
}

// 出栈 
void StackPop(Stack* ps)
{
	assert(ps);
	//若栈内为空,则无法出栈,需要判断栈内是否为空。
	assert(!StackEmpty(ps));
	//断言为真则继续
	ps->_top--;
}

// 获取栈顶元素 
STDataType StackTop(Stack* ps)
{
	assert(ps);
	//栈顶元素存在 --- 栈不为空
	assert(!StackEmpty(ps));
	//ps->_top 指向的是栈顶的下一个元素
	return ps->_a[ps->_top - 1];
}

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

	//栈内有效元素元素个数 --- 在入栈操作中,每进入一个 ps->_top++ 
	//                         在出栈操作中,每出去一个 ps->_top--; 
	//               所以  --- ps->_top 等价于站内有效元素
	return ps->_top;
}


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

	free(ps->_a);//数组是由 malloc 开辟而来的,需要使用 free 释放
	ps->_a = NULL;
	ps->_capacity = 0;
	ps->_top = 0;
}

 test.c

#include"stack.h"

void teat()
{
	Stack st;
	StackInit(&st);
	StackPush(&st, 1);
	StackPush(&st, 2);

	printf("%d\n", StackTop(&st));

	StackPush(&st, 3);
	StackPush(&st, 4);
	StackPush(&st, 5);

	while (!StackEmpty(&st))
	{
		printf("%d ", StackTop(&st));
		StackPop(&st);
	}

	StackDestroy(&st);


}
int main()
{
	teat();
	return 0;
}

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

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

相关文章

Origin中log2的计算,设置以2为底的log坐标

使用高中的换底公式即可&#xff0c;把2的底换成10的底计算 ![在这里插入图片描述](https://img-blog.csdnimg.cn/5747fdbd2b5c43f095d716092fd17124.png

模式介绍和基本管理

模式介绍&#xff1a; 用户的模式(SCHEMA&#xff09;指的是用户账号拥有的对象集&#xff0c;在概念上可将其看作是包含表、 视图、索引和权限定义的对象。在 DM 中&#xff0c;一个用户可以创建多个模式&#xff0c;一个模式中的对象 &#xff08;表、视图等&#xff09;可以…

【深度学习】- 作业2: MNIST手写数字识别

课程链接: 清华大学驭风计划 代码仓库&#xff1a;Victor94-king/MachineLearning: MachineLearning basic introduction (github.com) 驭风计划是由清华大学老师教授的&#xff0c;其分为四门课&#xff0c;包括: 机器学习(张敏教授) &#xff0c; 深度学习(胡晓林教授), 计算…

stata软件基本操作

一、stata软件介绍 Stata是一个用于分析和管理数据的功能强大又小巧玲珑的实用统计分析软件&#xff0c;由美国计算机资源中心&#xff08;Computer Resource Center&#xff09;研制。它同时具有数据管理软件、统计分析软件、绘图软件、矩阵计算软件和程序语言的特点&#xf…

二叉树的相关知识

1.树概念及结构 1.1树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因 为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 有一个特殊的结点&#…

Typora Mac版本安装 Pandoc 导出文件为word格式(windows可通用)

今天在和一位商务小伙伴对接的时候&#xff0c;需要提供一份 word 版本的初稿。对于习惯了使用 支持 markdown 语法的 typora 来说&#xff0c;复制粘贴到 word 是不可能的。 可以通过 “导出” 功能&#xff0c;选择将当前文件导出为 “word” 格式&#xff0c;这个过程有个小…

通过CSS实现炫酷效果,让你的网页不再平淡无奇

通过CSS实现炫酷效果&#xff0c;让你的网页不再平淡无奇 (一)CSS基础1.1CSS介绍1.2CSS样式1.3CSS 格式 &#xff08;二&#xff09;CSS 选择器2.1标签选择器2.2类选择器2.3层级选择器2.4id选择器2.5组选择器2.6伪类选择器2.7通配符选择器 &#xff08;三&#xff09;样式表引入…

【自然语言处理】 - 作业3: 文本情感分析

课程链接: 清华大学驭风计划 代码仓库&#xff1a;Victor94-king/MachineLearning: MachineLearning basic introduction (github.com) 驭风计划是由清华大学老师教授的&#xff0c;其分为四门课&#xff0c;包括: 机器学习(张敏教授) &#xff0c; 深度学习(胡晓林教授), 计算…

C++的继承

继承 1.继承的概念及定义1.1继承的概念1.2 继承定义1.2.1定义格式1.2.2继承关系和访问限定符1.2.3继承基类成员访问方式的变化 2.基类和派生类对象赋值转换3.继承中的作用域4.派生类的默认成员函数5.继承与友元6. 继承与静态成员7.复杂的菱形继承及菱形虚拟继承 1.继承的概念及…

舒适交友 - 什么样的婚姻最舒服 稳态婚姻

人人都是心理学家,mbti等_个人渣记录仅为自己搜索用的博客-CSDN博客 人生两大目标: 生产力提升 让身边的人快乐. 激动 兴奋 不一定 舒适 开心 幸福 安全感 平静 宁静 祥和 婚姻 稳态 041 探秘“情绪”——如何确定只有六种基本情绪&#xff1f; - 知乎 ( 6种原始情绪&am…

chatgpt赋能Python-python_dilate

Python中的dilate操作&#xff1a;了解该操作及其应用 在计算机视觉领域&#xff0c;dilate操作是一种常用的图像处理技术。在Python中&#xff0c;我们可以使用OpenCV库来实现dilate操作。本文将介绍dilate操作的基本概念&#xff0c;讨论其应用及如何使用Python进行实现。 …

C++爱好者的自我修养(13.1):一维数组——简介,声明,初始化(赋值)

文章目录 1.什么是数组&#xff1f;2.数组的声明2.1格式2.2特别注意&#xff1a;有效下标值的重要性 3.数组的初始化&#xff08;赋值&#xff09;3.1格式3.2 C11新增的初始化方法规则功能3.2.1 等号的省略3.2.2 当大括号内无东西3.2.3 禁止缩窄转换 1.什么是数组&#xff1f; …

Kafka实时数据同步

目录 1 概述 2 捕获Oracle数据到Kafka 2.1 数据捕获设置 2.2 数据发布任务设置 2.3 捕获到发布数据流映射 2.4 查看任务执行日志 3 订阅Kafka数据到ClickHouse 3.1 数据订阅设置 3.2 数据加载设置 3.3 订阅到加载数据流映射 3.4 查看任务执行日志 4 校验数据一致性 …

GEE:GEDI数据提取值到矢量区域和点

作者:CSDN @ _养乐多_ 本文将介绍GEDI数据集从GEE上下载到本地,并将每一个激光点的值提取为一个矢量区域,并提取值到矢量区域的方法。 文章目录 一、GEDI数据下载二、GEDI数据栅格矢量化三、提取值到区域四、提取栅格值到点五、空间插值一、GEDI数据下载 GEDI数据下载链接:…

80个Python练手小项目;AI开发者的总结与反思;B站免费Stable Diffusion视频教程;五问ChatGPT+医学影像 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 『美团大模型已秘密研发数月』在仅剩一年的窗口期里努力奔跑 5月18日下午&#xff0c;美团内部召开大模型技术分享会&#xff0c;美团…

【深度学习】- 作业5: Didi交通场景-车辆预测

课程链接: 清华大学驭风计划 代码仓库&#xff1a;Victor94-king/MachineLearning: MachineLearning basic introduction (github.com) 驭风计划是由清华大学老师教授的&#xff0c;其分为四门课&#xff0c;包括: 机器学习(张敏教授) &#xff0c; 深度学习(胡晓林教授), 计算…

ONVIF协议了解

第一部分:ONVIF理论基础 一&#xff0e; 为什么要用ONVIF协议&#xff1a; IPC厂商主流的遵循的是RTSP协议进行推流&#xff0c;那么RTSP最重要的就是RTSP的URL地址。但是各个厂商的URL地址格式都不一样&#xff0c;所以就诞生了一个标注协议—ONVIF。ONVIF协议的出现&#x…

开源赋能 普惠未来|QUICKPOOL诚邀您参与2023开放原子全球开源峰会

QUICKPOOL算力调度系统的诞生和发展&#xff0c;为广大的算力领域从业者和技术开发者&#xff0c;提供了一条中国技术路线&#xff0c;并与IBM LSF、SLURM、PBS、SGE等产品&#xff0c;共同助力全球算力发展。QUICKPOOL算力调度系统成熟、稳定&#xff0c;具备“超算&智算”…

MATLAB 搜索某一点的K邻近点(12)

MATLAB 搜索某一点的K邻近点(12) 前言一、算法介绍1.1 :无序点云的K邻近点搜索1.2 :有序点云的K邻近点搜索二、具体实现示例2.1 算法一 (含详细注释)2.2 算法二 (含详细注释)前言 在点云处理中,最基本的算法之一就是搜索某一点的近邻点(1个最近或多个邻近),这在重…

MySQL数据库学习笔记(八)实验课五之数据库系统设计

一上来就实验课五了&#xff0c;实验课四呢&#xff1f;实验课四的内容是添加索引&#xff0c;差不多就是那样。 这次实验课的内容感觉就有点硬核了&#xff0c;数据库系统设计。 重点&#xff1a; 记录下我在实验里面遇到的一些问题 1&#xff0c;E-R图绘制 我是用drawio绘…