【数据结构】栈的定义与实现(附完整运行代码)

news2024/11/14 23:58:20

目录

一、栈的定义

二、顺序栈 链栈比较

三、栈的实现(顺序栈)

3.1 ❥ 定义栈结构

3.2 ❥ 初始化

3.3 ❥ 销毁

3.4 ❥ 插入(入栈)

3.5 ❥ 删除 (出栈)  

3.6 ❥ 获取栈顶元素

3.7 ❥ 判空

3.8 ❥ 获取数据个数

四、完整运行代码

stack.h

stack.c

test.c


一、栈的定义

栈是一种特殊的线性表,其只允许在固定的一端进行插入删除元素操作。

进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。

栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

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

举例:

生活中我们装羽毛球的筒就是后进先出的例子,后放进的羽毛球先拿出来。

二、顺序栈 链栈比较

栈可以用数组实现,也可以用单链表或者双向链表实现。

用数组实现的栈称为顺序栈,用链表实现的栈称为链式栈

现在共有3种结构,选哪种更优呢?

首先排除双向链表。

因为单链表能实现,用双向链表就会浪费空间,少维护一个指针也更方便。


而数组和单链表实现栈各有好处,二者效果等同。

如果非要选择一个,选择数组更优一些。

数组的缺点只有一个:就是扩容。扩容虽然自身有消耗,但影响不大。况且并不是有数据插入就要扩容。

而数组的更优在于:cpu高速缓存命中率更高,所以选数组更好一些。(若是没有缓存率这一点,选链表)

三、栈的实现(顺序栈)

3.1 ❥ 定义栈结构

代码如下:

typedef int STDataType;

//定义栈结构
typedef struct stack
{
	STDataType* a;  //指向数组元素的指针
	int top;	   //有效数据个数
	int capacity;  //容量大小
}ST;

3.2 ❥ 初始化

为了防止使用出现错误,首先我们要对栈进行初始化操作,构造一个空栈。

思路:

  • 先将结构体变量的地址传给初始化函数
  • 然后将结构体里的数组指针初始化为NULL
  • 最后再把数据个数和容量大小都初始化为0

代码如下:

//初始化
void STInit(ST* ps)//传的是实参的地址,因为形参是实参的一份临时拷贝
{
	ps->a = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

易错点:关于top指针指向栈顶元素还是指向栈顶元素的下一个位置?

这里取决于自己定义。

  • top如果指向栈顶元素,那初始化top的时候就不能为0 (因为top为0时无法确定到底是有数据还是没有数据)
  • top如果指向栈顶元素的下一个,那初始化top的时候可以指向0

两种初始化方式想取哪一种都可以,但要搞清楚它们之间的关系(前后要求匹配)

3.3 ❥ 销毁

销毁的目的是:当我们使用完栈后,就要释放栈所占用的内存空间,还给操作系统

思路:

  • 首先进行断言,防止传入空指针(空地址)
  • 释放动态开辟的空间,并把指针置空,防止野指针发生未定义行为
  • 最后把容量和数据个数置为0(也可以不管,但是一般为了规范,都会把所有的成员做清理,除非是在销毁函数中做访问操作会出现错误)

代码如下:

//销毁
void STDestory(ST* ps)
{
	assert(ps);

	free(ps->a);
	ps->a = NULL;

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

3.4 ❥ 插入(入栈)

思路:

  • 我们要进行插入操作,就要动态申请空间,申请空间前,要先进行断言,防止传入空指针
  • 动态开辟一块空间,进行插入操作。为了防止开辟空间不够,我们需要持续扩容,所以用realloc函数,且每次开辟空间为原来的2倍
  • realloc前应先判断是否为首次开辟,因为若是头一次开辟的话,0*2一直为0,就等于没有开辟
  • 所以这里我们用三目运算,若是头一次开辟,直接给4个空间大小;若不是,就2倍增长。
  • 开辟完之后我们还要进行指针判断,防止开辟失败传入空指针
  • 若开辟成功,我们将数据入栈(也就是写入数组)

代码如下:

//插入(入栈)
void STPush(ST* ps, STDataType x)
{
	assert(ps);

	//扩容 开辟空间
	if (ps->capacity == ps->top)
	{
		// 三目运算符  等于0开辟4个字节 不等于0原空间大小*2
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->a, newcapacity * sizeof(STDataType));
		
		//开辟失败
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(1);
		}
		
		//开辟成功
		ps->capacity = newcapacity;
		ps->a = tmp;

	}	

	//入栈
	ps->a[ps->top] = x;
	ps->top++;

}

易错提醒:

开辟空间的条件这里写的是:ps->capacity==ps->top

原因:

因为我们这里是把top初始化为0了。当top初始化为0时,top跟size的意思一样(注意下标)

  • 若top=-1,top+1=capacity
  • 若top=0,top=capacity

哪种写法都可以,看初始化时top为-1还是0

3.5 ❥ 删除 (出栈)  

思路:

  • 删除前应先进行断言,防止传入空指针
  • 还要断言栈内元素是否为空,如果为空的话,就没办法进行出栈操作
  • 删除只需要将top指针往前挪动一位即可(因为top代表有效元素个数)

代码如下:

// 删除(出栈)
void STPop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);

	ps->top--;
}

插入删除端的固定:

具体插入删除端在哪里根据自己所选的结构有关。

  • 数组:插入删除端在尾
  • 单链表:插入删除端在头
  • 双向链表:插入删除端在头尾都可以

3.6 ❥ 获取栈顶元素

思路:

  • 获取之前先进行断言是否为空指针
  • 也需要断言栈内是否有元素
  • 然后返回top前一个下标位置(因为top用作下标表示的是栈顶下一个元素的位置)

代码如下:

//获取栈顶元素
STDataType STTop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);

	return ps->a[ps->top--];
}

3.7 ❥ 判空

思路:

  • 先进行断言
  • 判断top是否为0,为0则栈空,不为0则栈不为空

代码如下:

//判断栈是否为空
bool STEmpty(ST* ps)
{
	assert(ps);

	return ps->top == 0;
}

3.8 ❥ 获取数据个数

思路:

  • 先进行断言
  • 返回top(top表示有效数据个数)

代码如下:

//获取数据个数
int STSize(ST* ps)
{
	assert(ps);

	return ps->top;
}

四、完整运行代码

stack.h

#pragma once

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


typedef int STDataType;

//定义栈结构
typedef struct stack
{
	STDataType* a;  //指向数组元素的指针
	int top;	   //有效数据个数
	int capacity;  //容量大小
}ST;


//初始化
void STInit(ST*ps);  //传的是实参的地址,因为形参是实参的一份临时拷贝

//销毁
void STDestory(ST*ps);

//插入(入栈)
void STPush(ST* ps, STDataType x);//插入端固定,只能在一端进行插入

// 删除(出栈)
void STPop(ST * ps);//删除端也固定,只能在一端进行删除

//获取栈顶元素
STDataType STTop(ST* ps);

//判断栈是否为空
bool STEmpty(ST* ps);

//获取数据个数
int STSize(ST* ps);

stack.c

#define _CRT_SECURE_NO_WARNINGS 1

#include"stack.h"

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



//销毁
void STDestory(ST* ps)
{
	assert(ps);

	free(ps->a);
	ps->a = NULL;

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

//插入(入栈)
void STPush(ST* ps, STDataType x)
{
	assert(ps);

	//扩容 开辟空间
	if (ps->capacity == ps->top)
	{
		// 三目运算符  等于0开辟4个字节 不等于0原空间大小*2
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->a, newcapacity * sizeof(STDataType));
		
		//开辟失败
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(1);
		}
		
		//开辟成功
		ps->capacity = newcapacity;
		ps->a = tmp;

	}	

	//入栈
	ps->a[ps->top] = x;
	ps->top++;

}

// 删除(出栈)
void STPop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);

	ps->top--;
}

//获取栈顶元素
STDataType STTop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);

	return ps->a[ps->top--];
}

//判断栈是否为空
bool STEmpty(ST* ps)
{
	assert(ps);

	return ps->top == 0;
}

//获取数据个数
int STSize(ST* ps)
{
	assert(ps);

	return ps->top;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include"stack.h"

int main()
{
	//创建结构体变量s
	ST s;

	//初始化
	STInit(&s);

	//插入(入栈)
	STPush(&s, 1);
	STPush(&s, 2);
	STPush(&s, 3);
	STPush(&s, 4);

	// 删除(出栈)
	STPop(&s);

	//获取栈顶元素
	STDataType ret=STTop(&s);

	//判断栈是否为空
	bool h=STEmpty(&s);

	//获取数据个数
	int size=STSize(&s);

	//销毁
	STDestory(&s);

	return 0;
}

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

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

相关文章

Linux操作系统进程同步的几种方式及基本原理

1&#xff0c;进程同步的几种方式 1.1信号量 用于进程间传递信号的一个整数值。在信号量上只有三种操作可以进行&#xff1a;初始化&#xff0c;P操作和V操作&#xff0c;这三种操作都是原子操作。 P操作(递减操作)可以用于阻塞一个进程&#xff0c;V操作(增加操作)可以用于…

C++哈希表、哈希桶的实现以及模拟实现封装unordered_map 和 unordered_set 位图 布隆过滤器 哈希切割相关

文章目录 unordered系列关联式容器unordered_mapunordered_map的接口说明 unordered_setset 与 unordered_set的效率比较 底层结构哈希概念哈希冲突哈希函数常见哈希函数哈希冲突解决闭散列 —— 开放定址法哈希表的插入线性探测二次探测 哈希表的闭散列实现哈希表的结构插入代…

Redis报错:MISCONF Redis is configured to save RDB snapshots

错误提示内容&#xff1a; 2024-06-25 16:30:49 : Connection: Redis_Server > [runCommand] PING 2024-06-25 16:30:49 : Connection: Redis_Server > Response received : -MISCONF Redis is configured to save RDB snapshots, but it is currently not able to pers…

Java高级重点知识点-13-数据结构、List集合、List集合的子类

文章目录 数据结构List集合List的子类&#xff08;ArrayList集、LinkedList集&#xff09; 数据结构 栈 stack,又称堆栈&#xff0c;它是运算受限的线性表&#xff0c;其限制是仅允许在标的一端进行插入和删除操作&#xff0c;不允许在其他任何位置进行添加、查找、删除等操作…

Verilog描述一个带有异步置位和异步清零的D触发器

1 带有异步置位和异步清零的D触发器的真值表&#xff1a; 2 Verilog代码描述 module DFF_SR(CLK, D, Rd, Sd, Q, QN);input CLK, D, Rd, Sd;output Q, QN;reg Q_DFF;always (posedge CLKor negedge Rd or negedge Sd)beginif(!Rd)Q_DFF < 1b0;else if(!Sd)Q_DFF < 1b1;e…

问题:泡泡纱、市布属()织物。 #笔记#知识分享#职场发展

问题&#xff1a;泡泡纱、市布属&#xff08;&#xff09;织物。 A.纯棉 B.化纤 C.涤棉 D.纯麻 参考答案如图所示

APP软件系统的开发流程

APP软件系统的开发是一个复杂的过程&#xff0c;需要多方面的知识和技能。建议选择专业的开发团队进行开发&#xff0c;以确保APP的质量和成功。APP软件系统的开发流程通常包括以下几个阶段。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合…

抖音直播违规规定有哪些?(直播违禁词汇总表)

全民直播的同时也有不少新手直播玩家处处碰壁,直播间没人气,直播不知道说什么甚至直播间被封。 收到直播封禁通知的朋友,轻者封禁直播账号两三天,严重着可能永久封禁直播间! 今天我们重点来说说直播间被封是怎么回事?如何避免抖音直播间被封?抖音直播间违规规定有哪些?抖音…

2024年最新机动车签字授权人考试题库。

31."简易瞬态工况法"所使用的五气分析仪的温度范图:分析系统及相关部件应在&#xff08; &#xff09;。 A.0-40℃ B.0-50℃ C.0-60℃ D.-10-40℃ 答案:A 32.稀释氧传感器环境空气量程检测时的读数值位于&#xff08; &#xff09;%vol范围之外时&#xff0c;应…

链家房屋数据爬取与预处理-大数据采集与预处理课程设计

芜湖市链家二手房可视化平台 成品展示 重点说明 1.数据特征数量和名称、数据量 数据特征数量&#xff1a;14&#xff1b; 名称&#xff1a;小区名、价格/万、地区、房屋户型、所在楼层、建筑面积/平方米、户型结构、套内面积、建筑类型、房屋朝向、建筑结构、装修情况、梯户…

Linux驱动开发笔记(十一)tty子系统及其驱动

文章目录 前言一、串口驱动框架1.1 核心数据结构1.2 数据处理流程 二、驱动编写1. 设备树的修改2. 相关API函数3. 驱动框架4. 具体功能的实现4.1 出入口函数的编写4.2 读写函数 前言 之前已经讲过应用层的应用&#xff0c;接下来我们继续进行驱动的学习。其实实际上我们很少主动…

艺术巨匠妙笔下的红酒:诗意流淌的色彩,邂逅灵魂的瞬间

在艺术的世界里&#xff0c;红酒不仅是一种饮品&#xff0c;更是艺术家们笔下的灵感之源。当那深邃的葡萄汁在画布上流淌&#xff0c;一种不同的色彩诗意便悄然绽放。今天&#xff0c;就让我们一起走进这个充满色彩与诗意的世界&#xff0c;探寻艺术大师笔下的红酒魅力&#xf…

基于AdaBoost的旋转机械故障诊断(Python)

前置文章&#xff1a; 将一维机械振动信号构造为训练集和测试集&#xff08;Python&#xff09; https://mp.weixin.qq.com/s/DTKjBo6_WAQ7bUPZEdB1TA 旋转机械振动信号特征提取&#xff08;Python&#xff09; https://mp.weixin.qq.com/s/VwvzTzE-pacxqb9rs8hEVw import…

visual studio打包QT工程发布exe安装包

一、实验环境 软件版本下载链接visual studioMicrosoft Visual Studio Community 2022 (64 位) - Current 版本 17.7.5QTv6.6.3NSISv3.10官网 或 百度云1234Windows11 二、程序准备 1、程序生成 使用 visual studio 打开工程&#xff0c;选择 Release 模式后&#xff0c;点…

【面试题】MySQL数据库

目录 什么是视图&#xff0c;视图的作用是什么&#xff1f;什么是索引&#xff1f;MySQL中有哪些类型的索引&#xff1f;简述索引设计原则&#xff1f;简述索引的数据结构&#xff1f;简述Hash 和 B 树索引的区别&#xff1f;列出MySQL中导致索引失效的情况&#xff1f;简述数据…

永洪bi里topN的设置/用法

要实现的效果&#xff1a;实现通过输入参数&#xff0c;进行图表top的排序筛选 图示&#xff1a; 筛选前&#xff1a; 输入3&#xff0c;看top3的值&#xff1a; 输入-3&#xff0c;看倒数3个的值&#xff1a; 设置步骤&#xff1a; 1️⃣&#xff1a;添加一个“文本参数组件…

干货!车间生产管理的主要内容及管理方法,建议收藏

作为一名车间主管&#xff0c;我深知车间现场管理对于整个生产流程的重要性。车间是企业生产的核心区域&#xff0c;是产品从原材料转化为成品的关键环节。因此&#xff0c;有效的车间现场管理不仅能确保生产过程的顺利进行&#xff0c;还能提高生产效率、降低成本&#xff0c;…

招聘统计关于候选人的体验

我们生活在一个由感觉驱动的世界里。企业花费大量的时间和资源来改变用户体验、员工体验和产品用户体验。在招聘中&#xff0c;最重要的是候选人的体验。面对不断变化的候选人期望和招聘技术&#xff0c;作为与组织建立强烈关系的大门&#xff0c;改善候选人的感受是一个持续的…

python无法安装scipy怎么办

python安装scipy时出现以下错误&#xff1a; from scipy.misc import imread Traceback (most recent call last):File "D:/Pyproject/qq_Spider/create_cloud.py", line 14, in <module>from scipy.misc import imread ModuleNotFoundError: No module named …

功能测试【测试用例模板、Bug模板、手机App测试★】

功能测试 Day01 web项目环境与测试流程、业务流程测试一、【了解】web项目环境说明1.1 环境的定义&#xff1a;项目运行所需要的所有的软件和硬件组合1.2 环境(服务器)的组成&#xff1a;操作系统数据库web应用程序项目代码1.3 面试题&#xff1a;你们公司有几套环境&#xff1…