(超详细)数据结构——“栈”的深度解析

news2024/11/24 11:09:06
前言:

   在前几章我们介绍了线性表的基本概念,也讲解了包括顺序表,单链表,双向链表等线性表,相信大家已经对线性表比较熟悉了,今天我们要实现线性表的另一种结构——栈。

1.栈的概念

    栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFOLast In First Out)的原则。这里的栈与内存中的栈在结构上是一致的,它们提取数据和存放数据也叫出栈和压栈。

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

2.栈的实现 

   栈的实现可以选择使用链表或者数组,这两种结构都可以很好的实现栈的各种操作,相对而言,数组是更好的选择,因为栈的插入只需要对结构进行尾插,而数组尾插的代价相较于链表来说没有那么大。

3.代码实现 

   为了方便管理,我们将栈的实现分为三个文件,分别是test.c ,Stack.c ,Stack.h(stack中译为堆叠,也就是栈的意思) ,由于我们选择使用数组来实现栈,所以在数据结构中我们就使用动态顺序表,顺序表中要包含顺序表空间大小,一个指向这块空间的指针和top来表示栈顶,而这个数据的类型是视情况而定的,我们使用typedef对数组中的元素类型改名,使栈存储的数据类型更加灵活,为了方便使用,我们也将栈类型改名为ST:

typedef int STDataType;
typedef struct Stack
{
	STDataType* arr;
	int top;
	int capacity;//表示当前空间大小

}ST;

实现了栈的基本结构之后,我们接下来要实现栈的各种操作,例如栈的压栈和出栈等操作。

3.1 栈的初始化 

   在程序刚开始执行使,栈内部的所有成员都没有初始化,它们的值都是不确定的,而不确定意味着不可控,我们后续需要通过这些成员的值来判断执行一些操作,例如表示数组的空间大小capacity变量,如果它的值是不确定的,那么我们也无法对数组执行有效操作,所以我们要对它进行初始化,而刚开始栈是空的,所以我们让指向栈的指针指向空,元素为0个:

void STInit(ST* pst)
{
	assert(pst);
	pst->arr = NULL;
	pst->capacity = 0;
	pst->top = 0;
}//初始化

3.2 栈的销毁

   我们栈的空间使用的的是顺序表结构实现的,而顺序表的空间都是在堆上开辟的,所以我们需要手动将这些空间释放:

void STDestroy(ST* pst)
{
	assert(pst);

	free(pst->arr);
	pst->arr = NULL;
	pst->capacity = pst->top = 0;
}//销毁

3.3 压栈操作 

   压栈就是进栈的意思,对栈进行压栈操作之前,我们要判断栈空间够不够,如果不够,我们需要手动从堆上开辟一块空间,而一次开辟的空间是有限的,将空间开辟得太大也会造成空间浪费,所以我们判断在空间不够时使用realloc函数重新开辟一块更大的空间,而插入操作则比较简单,只需要在数组中top指向的位置将我们要插入的数据插入,再让top加一就可以了:

void STPush(ST* pst, STDataType x)
{
	assert(pst);
	if (pst->capacity == pst->top)
	{
		int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		STDataType* ret = (STDataType*)realloc(pst->arr, newcapacity * sizeof(STDataType));
		if (ret == NULL)
		{
			perror("realloc fail");
			return;
		}
		pst->capacity = newcapacity;
		pst->arr = ret;
	}
	pst->arr[pst->top++] = x;
}//压栈

3.4 出栈操作 

    出栈操作也就是删除栈顶的元素,这个操作比较简单,只需要让top减一,因为我们在取数据时,只取top下面的数据,top上面的数据则默认不在栈内,这样就相当于我们将这个元素删除了:

void STPop(ST* pst)
{
	assert(pst);
	pst->top--;
}//删除

3.5 栈顶 

 有时我们频繁对栈进行插入和删除操作,我们需要查看栈顶情况,就可以使用这个方法,,这个方法的实现也相对简单,只需要返回栈中top下标的下一个 元素,因为top始终指向栈顶元素的下一个位置,我们插入元素也是先将元素放到下标为top的位置中,再让top加一:

STDataType STTop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);
	return pst->arr[pst->top - 1];
}//栈顶

3.6 判空 

  我们有时要对栈进行置空操作,如果不确定栈何时为空就可以使用这个方法,判空操作只需要判断top是否为0就可以了,如果为零,就为真,返回true,如果不为空,就为假返回false:

bool STEmpty(ST* pst)
{
	assert(pst);
	return pst->top == 0;
}//判空

3.7 栈的大小 

   我们前面提到了,top就是栈的大小,如果我们直接查看top不是更快吗,为什么要单独写一个方法呢,事实上我们单独实现一个方法是为了方便统一操作,要执行何种操作,只需要调用一个方法就可以实现:

int STSize(ST* pst)
{
	assert(pst);
	return pst->top;
}//大小

3.8 测试

实现完这些方法之后,我们要测试一下我们的代码有没有问题:

经过我们测试,这些方法都没有问题,本期栈的讲解到这就结束了,是不是比前几期简单一些呢,我们亲自上手就知道了,代码放在下面感兴趣的小伙伴们可以试试哦。 

Stack.h :

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int STDataType;
typedef struct Stack
{
	STDataType* arr;
	int top;
	int capacity;//表示当前空间大小

}ST;
void STInit(ST* pst);//初始化

void STDestroy(ST* pst);//销毁

void STPush(ST* pst, STDataType x);//压栈

void STPop(ST* pst);//删除

STDataType STTop(ST* pst);//栈顶元素

bool STEmpty(ST* pst);//判空

int STSize(ST* pst);//大小

Stack.c :

#define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"

void STInit(ST* pst)
{
	assert(pst);
	pst->arr = NULL;
	pst->capacity = 0;
	pst->top = 0;
}//初始化

void STPush(ST* pst, STDataType x)
{
	assert(pst);
	if (pst->capacity == pst->top)
	{
		int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		STDataType* ret = (STDataType*)realloc(pst->arr, newcapacity * sizeof(STDataType));
		if (ret == NULL)
		{
			perror("realloc fail");
			return;
		}
		pst->capacity = newcapacity;
		pst->arr = ret;
	}
	pst->arr[pst->top++] = x;
}//压栈

void STPop(ST* pst)
{
	assert(pst);
	pst->top--;
}//删除

STDataType STTop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);
	return pst->arr[pst->top - 1];
}//栈顶

bool STEmpty(ST* pst)
{
	assert(pst);
	return pst->top == 0;
}//判空

int STSize(ST* pst)
{
	assert(pst);
	return pst->top;
}//大小

void STDestroy(ST* pst)
{
	assert(pst);

	free(pst->arr);
	pst->arr = NULL;
	pst->capacity = pst->top = 0;
}//销毁

test.c :

#define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"
void test()
{
	ST s;

	STInit(&s);
	printf("插入四个元素\n");
	STPush(&s, 1);
	STPush(&s, 2);
	STPush(&s, 3);
	STPush(&s, 4);
	
	printf("栈顶元素为:%d\n", STTop(&s));
	printf("%d个元素\n", STSize(&s));
	while (!STEmpty(&s))
	{
		printf("%d ", STTop(&s));
		STPop(&s);

	}
	STDestroy(&s);
}

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

 

 

 

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

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

相关文章

AI是如何与快充技术结合的?

针对AI技术在快充领域的运用&#xff0c;我们可以进一步深入探讨AI如何与快充技术结合&#xff0c;提升充电效率和用户体验。以下是一些具体的AI技术在快充领域的应用场景&#xff1a; 一、智能充电算法 学习充电模式&#xff1a;AI算法可以学习用户的充电习惯&#xff0c;比…

批量文件名修改软件:一键解决同一编码多型号文件分类与命名难题,高效管理文件

在数字化时代&#xff0c;图片文件已经成为我们工作中不可或缺的一部分。然而&#xff0c;当面对成百上千个同一编码下不同型号的图片文件时&#xff0c;如何快速、准确地进行分类和命名&#xff0c;成为了许多职场人士头疼的问题。现在&#xff0c;我们为您带来了一款神奇的批…

智能环境监测与数据分析系统

项目名称&#xff1a;智能环境监测与数据分析系统 一、引言 随着科技的发展和人们环保意识的增强&#xff0c;对环境监测的需求日益增加。传统的环境监测手段往往存在数据收集不及时、数据分析不准确等问题。因此&#xff0c;设计一个智能环境监测与数据分析系统具有重要的现…

如何在 SQL 中删除一条记录?

如何在 SQL 中删除一条记录&#xff1f; 在 SQL 中&#xff0c;您可以使用DELETE查询和WHERE子句删除表中的一条记录。在本文中&#xff0c;我将向您介绍如何使用DELETE查询和WHERE子句删除记录。我还将向您展示如何一次从表中删除多条记录 如何在 SQL 中使用 DELETE 这是使…

GMSB文章八:微生物中介分析

欢迎大家关注全网生信学习者系列&#xff1a; WX公zhong号&#xff1a;生信学习者Xiao hong书&#xff1a;生信学习者知hu&#xff1a;生信学习者CDSN&#xff1a;生信学习者2 介绍 中介分析&#xff08;Mediation Analysis&#xff09;是一种统计方法&#xff0c;用于研究一…

Linux基础篇——目录结构

基本介绍 Linux的文件系统是采用级层式的树状目录结构&#xff0c;在此结构中的最上层是根目录"/"&#xff0c;然后在根目录下再创建其他的目录 在Linux中&#xff0c;有一句经典的话&#xff1a;在Linux世界里&#xff0c;一切皆文件 Linux中根目录下的目录 具体的…

新能源行业知识体系-------主目录-----持续更新

本文相当于目录方便快速检索内容&#xff0c;没有实际内容&#xff0c;只做索引 文章目录 一、电力市场概论二、蒙西电网需求侧响应三、蒙西电网市场结算V2.0 一、电力市场概论 是学习清华大学电力市场概论(2024年春)的学习笔记&#xff0c;详细了解电力市场是如何利用经济学知…

远程桌面无法复制粘贴文件到本地怎么办?

远程桌面不能复制粘贴问题 Windows远程桌面为我们提供了随时随地访问文件和数据的便捷途径&#xff0c;大大提升了工作和生活的效率。然而&#xff0c;在使用过程中&#xff0c;我们也可能遇到一些问题。例如&#xff0c;在通过远程桌面传输文件时&#xff0c;常常会出现无法复…

Day7:.翻转字符串里的单词 151 卡码网:55.右旋转字符串

题目 151. 反转字符串中的单词 - 力扣&#xff08;LeetCode&#xff09; class Solution { public:// 移除多余空格void moveSpace(string& s) {// 定义快慢指针int slow 0;int fast 0;// 删除前导空格while (s.size() > 0 && fast < s.size() &&…

第2章-Python编程基础

#本章目标 1&#xff0c;了解什么是计算机程序 2&#xff0c;了解什么是编程语言 3&#xff0c;了解编程语言的分类 4&#xff0c;了解静态语言与脚本语言的区别 5&#xff0c;掌握IPO程序编写方法 6&#xff0c;熟练应用输出函数print与输入函数input 7&#xff0c;掌握Python…

204.贪心算法:分发饼干(力扣)

以下来源于代码随想录 class Solution { public:int findContentChildren(vector<int>& g, vector<int>& s) {// 对孩子的胃口进行排序sort(g.begin(), g.end());// 对饼干的尺寸进行排序sort(s.begin(), s.end());int index s.size() - 1; // 从最大的饼…

MySQL之索引失效的情况

什么情况下索引会失效&#xff1f; 违反最左前缀原则范围查询右边的列不能使用索引不要在索引列上进行运算操作字符串不加单引号导致索引失效以%开头的like模糊查询 什么情况下索引会失效&#xff1f; 示例&#xff0c;有user表如下 CREATE TABLE user (id bigint(20) NOT NU…

大语言模型(LLMs)全面学习指南,初学者入门,一看就懂!

大语言模型&#xff08;LLMs&#xff09;作为人工智能&#xff08;AI&#xff09;领域的一项突破性发展&#xff0c;已经改变了自然语言处理&#xff08;NLP&#xff09;和机器学习&#xff08;ML&#xff09;应用的面貌。这些模型&#xff0c;包括OpenAI的GPT-4o和Google的gem…

docker安装sqlserver2019

1、背景 由于要学习flink cdc&#xff0c;并且数据源是sqlserver&#xff0c;所以这里采用docker安装sqlserver。 2、安装步骤 &#xff08;1&#xff09;建目录 // 创建指定的目录 mkdir sqlserver// 进入该目录 cd sqlserver// 创建/data/mssql目录 mkdir -p /data/mssql…

电子电路学习笔记(3)三极管

部分内容参考链接&#xff1a; 电子电路学习笔记&#xff08;5&#xff09;——三极管_三极管 箭头-CSDN博客 模拟电子技术基础笔记&#xff08;4&#xff09;——晶体三极管_集电结的单向导电性-CSDN博客 硬件基本功-36-三极管Ib电流如何控制Ic电流_哔哩哔哩_bilibili 部分…

力扣最新详解5道题:两数之和三数之和四数之和

目录 一、查找总价格为目标值的两个商品 题目 题解 方法一&#xff1a;暴力枚举 方法二&#xff1a;对撞指针 二、两数之和 题目 题解 方法一&#xff1a;暴力枚举 方法二&#xff1a;哈希表法 三、三数之和 题目 题解 方法一&#xff1a;排序暴力枚举set去重 …

【JVM基础篇】垃圾回收

文章目录 垃圾回收常见内存管理方式手动回收&#xff1a;C内存管理自动回收(GC)&#xff1a;Java内存管理自动、手动回收优缺点 应用场景垃圾回收器需要对哪些部分内存进行回收&#xff1f;不需要垃圾回收器回收需要垃圾回收器回收 方法区的回收代码测试手动调用垃圾回收方法Sy…

二叉树第二期:堆的实现与应用

若对树与二叉树的相关概念&#xff0c;不太熟悉的同学&#xff0c;可移置上一期博客 链接&#xff1a;二叉树第一期&#xff1a;树与二叉树的概念-CSDN博客 本博客目标&#xff1a;对二叉树的顺序结构&#xff0c;进行深入且具体的讲解&#xff0c;同时学习二叉树顺序结构的应用…

Origin科学绘图软件最新版下载安装,Origin强大的科学研究工具

Origin软件&#xff0c;这款软件以其强大的数据分析和图形绘制功能&#xff0c;赢得了广大科研人员的青睐。无论是探索微观世界的化学研究&#xff0c;还是深究宏观现象的物理学分析&#xff0c;亦或是揭示生命奥秘的生物学探索&#xff0c;Origin软件都能为用户提供精准、高效…

Raccon:更好防侧信道攻击的后量子签名方案

1. 引言 安全社区已经开发出了一些出色的加密算法&#xff0c;这些算法非常安全&#xff0c;但最终&#xff0c;所有的数据都会被存储在硅和金属中&#xff0c;而入侵者越来越多地会在那里放置监视器来破解密钥。 破解加密密钥通常涉及暴力破解方法或利用实施过程中的缺陷。然…