数据结构——栈的实现

今天,我们来写一下关于栈的博文。

1.首先我们先了解一下什么是栈?

一:概念:

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

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

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

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

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

为了更好的理解,我们画个图辅助了解一下吧。

具体解释:

你看上面:

想要加数据的时候,就在栈顶入数据,此时叫压栈

再看,想要删数据的时候,是不是也得再栈顶出?此时叫出栈

同时,你是不是就发现了无论它是加还是删,遵循的规律都是后进先出

 

二:栈的实现

好了,有了上面的认识后,就可以进行实现部分了。

在此之前,我们首先得考虑考虑,我们得采用什么形式呢?是数组还是链表呢?

一般来说,两者都是可以的,但是使用数组的形式更优一些,对此我们在这里就以链表来实现它。
链式栈:可以用双向链表,但最好用单链表(用头那边当栈顶)
如果用的是数组的话,一般是尾部当栈顶

其实,感觉这里跟顺序表那些都差不多呢~

好了,至此,正式开始吧:

建立数组栈结构:

typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;
}ST;

初始化部分

void STInit(ST* ps)
{
	assert(ps);

	ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);
	if (ps->a == NULL)
	{
		perror("malloc fail");
		return;
	}

	ps->capacity = 4;
	ps->top = 0;   // top是栈顶元素的下一个位置

	//ps->top = -1;   // top是栈顶元素位置
}


但是这里有些问题:top指向的是栈顶的下一个,先放数据再++
还是栈顶位置,一开始就在0这个位置出发。先++再放数据。给-1位置

看下图:

那么,肯定有人疑惑为什么呢?

答:因为当初始化给0时,就代表栈顶有元素了,给-1的时候就表示栈为空。

你也可以那样想到数组那个,你看:

数组[0]的时候它是不是就代表已经有一个元素了,这个元素相当于就在第一个位置那样?

同样,当你希望初始化时不需要有数据(相当于联想到数组),当0时有一个数字,这时,你给-1,是不是相当于没有数据了?

有人有问了,当你给-1的话,不会变成野指针了吗?

其实这个问题不用担心,因为这里给-1的时候就要判断了。这里0去访问是合法的,但是刚初始化没有push的内容,就会有问题了,所以如果使用0的话,还需要做出处理。

总的来说,使用0还是-1都是没有强制性要求你,都是可以的,看个人喜好了。

这里使用的0的形式。

销毁部分:

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

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

这里销毁的时候,使用-1和0,ps->top就会有一点的区别了。

插入部分

void STPush(ST* ps, STDataType x)
{
	assert(ps);

	if (ps->top == ps->capacity)
	{
		STDataType* tmp = (STDataType*)realloc(ps->a,
			sizeof(STDataType) * ps->capacity*2);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}

		ps->a = tmp;
		ps->capacity *= 2;
	}

	ps->a[ps->top] = x;
	ps->top++;
}

解释:

在插入之前,我们先进行判断它是否已经满了,满了的话就扩容,反之不用。

插入的话,也比较简单,由于它只能在栈顶插入嘛。因为这里使用的0的形式

所以就直接找到栈顶的位置,插进去就可以了。

ps->a[ps->top] = x;
	ps->top++;

删除部分

void STPop(ST* ps)
{
	assert(ps);
	assert(!STEmpty(ps));

	ps->top--;
}

也由于只能栈顶先删,所以就减减top就可以了。

得出栈的大小部分

int STSize(ST* ps)
{
	assert(ps);

	return ps->top;
}

因为使用的是数组栈,我们又知道,数组是连续的,所以直接返回top所在的位置,就可以得出大小了。

判断空部分

bool STEmpty(ST* ps)
{
	assert(ps);

	return ps->top == 0;
}

因为使用的是0,即栈的下一个,当它栈顶的位置是0的时候,就代表它没有数据了,也就是空。

此时返回就好了。

另外,我们上面的删是不是也得判断一下是否空的情况对不对?如果它已经空了,那么还删的话,有什么意义?对吧?

所以可以看到上面的删除部分,我们使用了断言它不为空。

找尾部分

STDataType STTop(ST* ps)
{
	assert(ps);
	assert(!STEmpty(ps));

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

这是说,如果你要找尾的话,数组嘛,所以直接找下标就可以了。

好了,功能已经介绍完了。

现在来附上完整代码:

Stack部分

#define _CRT_SECURE_NO_WARNINGS 1
#include "Stack.h"

void STInit(ST* ps)
{
	assert(ps);
	ps->a = (StDatatype*)malloc(sizeof(StDatatype) * 4);
	if (ps->a == NULL)
	{
		perror("malloc fail");
		return;
	}
	ps->top = 0;
	ps->capacity = 4;
}

void Destory(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

void STPush(ST* ps,StDatatype x)
{
	if (ps->top== ps->capacity)
	{
		StDatatype* temp =(StDatatype*) realloc(ps->a, sizeof(StDatatype) * ps->capacity * 2);
		if (temp == NULL)
		{
			perror("realloc fail");
			return 0;
		}
		ps->a = temp;
		ps->capacity *= 2;
	}
	ps->a[ps->top] = x;
	ps->top++;
}
void STPop(ST* ps)
{
	assert(ps);
	assert(!STEmpty(ps));
	ps->top--;
}
int size(ST* ps)
{
	assert(ps);
	return ps->top;
}
bool STEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}
StDatatype STTop(ST* ps)
{
	assert(ps);
	assert(!STEmpty(ps));
	return ps->a[ps->top-1];
}

Stack.h部分

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
//
//typedef struct Stack
//{
//	int a[20];
//	int top;
//};

typedef char StDatatype;
typedef struct Stack
{
	StDatatype* a ;
	int top;
	int capacity;

}ST;

//ʼ
void STInit(ST* ps);
void Destory(ST* ps);
void STPush(ST* ps,StDatatype x);
void STPop(ST* ps);
int size(ST* ps);
bool STEmpty(ST* ps);
StDatatype STTop(ST* ps);
bool isValid(char* s);

测试部分:

#define _CRT_SECURE_NO_WARNINGS 1
#include "Stack.h"
int main()
{
	ST st;
	STInit(&st);
	STPush(&st,'(');
	STPush(&st, ']');
	bool ret = isValid(&s);
	
	if (ret == "false")
	{
		printf("no");
	}
	else
	{
		printf("yes");
	}
	

	Destory(&st);
	return 0;
}

好了,到了每次鸡汤部分:

你每一步都会算数的!

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

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

相关文章

uniapp 的uni.getRecorderManager() 录音功能小记

官网上明确说的是全局唯一并且只是获取对象&#xff0c;所以会导致一个问题就是&#xff0c;当你多个页面要用到这个对象的时候&#xff0c;会发现 onStop 方法会被覆盖&#xff0c;导致调用结果不是自己想要的 解决办法也简单粗暴&#xff0c;在需要用到的界面重新覆盖onStop…

Unity:删除注册表内的项目记录

然后WinR按键输入regedit 打开注册表 在注册表 HKEY CURRENT USER—>SOFTWARE—>Unity—>UnityEditor—>DefaultCompany —>language_Test 中&#xff0c;删除我们的之前存储的语言环境数据。在 “ 三、文本调用和替换 ” 测试时已经将语言环境存储到注册表中了…

标准应用 | 2025年网络安全服务成本度量实施参考

01 网络安全服务成本度量依据相关新变化 为了解决我国网络安全服务产业发展中面临的服务供需两方对于服务成本组成认知偏差较大、网络安全服务成本度量缺乏依据的问题&#xff0c;中国网络安全产业联盟&#xff08;CCIA&#xff09;组织北京赛西科技发展有限责任公司、北京安…

微信小程序map组件所有markers展示在视野范围内

注意&#xff1a;使用include-points属性不生效&#xff0c;要通过createMapContext实现 <template><view class"map-box"><map id"map" class"map" :markers"markers" :enable-traffic"true" :enable-poi&…

PLC实现HTTP协议JSON格式数据上报对接的参数配置说明

IGT-SER系列PLC通讯智能网关支持HTTP协议GET和POST、PUT请求模式。支持JSON格式的文件&#xff0c;也可以实现WebService的调用。 通常智能网关是HTTP协议的客户端&#xff0c;也可以同时作为HTTP的服务端。相关案例 作为客户端时支持触发、周期、混合等多种工…

微信小程序——创建滑动颜色条

在微信小程序中&#xff0c;你可以使用 slider 组件来创建一个颜色滑动条。以下是一个简单的示例&#xff0c;展示了如何实现一个颜色滑动条&#xff0c;该滑动条会根据滑动位置改变背景颜色。 步骤一&#xff1a;创建小程序项目 首先&#xff0c;使用微信开发者工具创建一个新…

Improving Language Understanding by Generative Pre-Training GPT-1详细讲解

Improving Language Understanding by Generative Pre-Training 2018.06 GPT-1 0.有监督、半监督、无监督 CV&#xff1a;ImageNet pre-trained model NLP&#xff1a;pre-trained model? 在计算机视觉中任务包含分类、检测、分割&#xff0c;任务类别数少&#xff0c;对应…

sql server cdc漏扫数据

SQL Server的CDC指的是“变更数据捕获”&#xff08;Change Data Capture&#xff09;。这是SQL Server数据库提供的一项功能&#xff0c;能够跟踪并记录对数据库表中数据所做的更改。这些更改包括插入、更新和删除操作。CDC可以捕获这些变更的详细信息&#xff0c;并使这些信息…

如何在 Ubuntu 22.04 上安装 Caddy Web 服务器教程

简介 Caddy 是一个开源的 Web 服务器&#xff0c;它支持静态和现代 Web 应用程序&#xff0c;使用预定义的配置规则&#xff0c;并为所有链接的域名自动启用 HTTPS。Caddy 使用 GO 语言编写&#xff0c;提供了用户友好的配置指令&#xff0c;使你既可以将其用作 Web 服务器&am…

《机器学习》——贝叶斯算法

贝叶斯简介 贝叶斯公式&#xff0c;又称贝叶斯定理、贝叶斯法则&#xff0c;最初是用来描述两个事件的条件概率间的关系的公式&#xff0c;后来被人们发现具有很深刻的实际意义和应用价值。该公式的实际内涵是&#xff0c;支持某项属性的事件发生得愈多&#xff0c;则该属性成…

边缘计算网关在机床设备数据采集中的应用

边缘计算网关是连接边缘设备和云端的一个中间节点&#xff0c;负责在边缘设备和云服务器之间进行数据传输和处理。它具备数据采集、数据处理、协议转换、数据存储、安全功能及远程管理等多种能力&#xff0c;是边缘计算系统中不可或缺的关键设备。 一、功能与优势 数据采集&a…

腾讯二面:MySQL的半同步是什么?不是MySQL的两阶段提交,那是什么?

前言 年后在进行腾讯二面的时候&#xff0c;写完算法的后问的第一个问题就是&#xff0c;MySQL的半同步是什么&#xff1f;我当时直接懵了&#xff0c;我以为是问的MySQL的两阶段提交的问题呢&#xff1f;结果确认了一下后不是两阶段提交&#xff0c;然后面试官看我连问的是啥都…

云计算基础,虚拟化原理

文章目录 一、虚拟化1.1 什么是虚拟化1.2 虚拟化类型 二 、存储虚拟化2.1 存储指标2.2 存储类型2.3 存储协议2.4 RAID 三、内存 i/O虚拟化3.1 内存虚拟化基本概念地址空间转换原理内存共享与隔离原理 3.2 I/O 虚拟化基本概念模拟&#xff08;Emulation&#xff09;方式半虚拟化…

【网络协议】IPv4 地址分配 - 第二部分

前言 在第 1 部分中&#xff0c;我们学习了 IPv4 地址的分配方式&#xff0c;了解了各种类型的 IPv4 地址&#xff0c;并进行了基础的子网划分&#xff08;Subnetting&#xff09;。在第 2 部分中&#xff0c;我们将继续学习子网划分&#xff0c;并引入一些新的概念。 【网络…

JAVA 使用apache poi实现EXCEL文件的输出;apache poi实现标题行的第一个字符为红色;EXCEL设置某几个字符为别的颜色

设置输出文件的列宽&#xff0c;防止文件过于丑陋 Sheet sheet workbook.createSheet(FileConstants.ERROR_FILE_SHEET_NAME); sheet.setColumnWidth(0, 40 * 256); sheet.setColumnWidth(1, 20 * 256); sheet.setColumnWidth(2, 20 * 256); sheet.setColumnWidth(3, 20 * 25…

Cursor 实战技巧:好用的提示词插件Cursor Rules

你好啊&#xff0c;见字如面。感谢阅读&#xff0c;期待我们下一次的相遇。 最近在小红书发现了有人分享这款Cursor提示词的插件&#xff0c;下面给各位分享下使用教程。简单来说Cursor Rules就是可以为每一个我们自己的项目去配置一个系统级别的提示词&#xff0c;这样在我们…

【简博士统计学习方法】第1章:3. 统计学习方法的三要素

3. 统计学习方法的三要素 3.1 监督学习的三要素 3.1.1 模型 假设空间&#xff08;Hypothesis Space&#xff09;&#xff1a;所有可能的条件概率分布或决策函数&#xff0c;用 F \mathcal{F} F表示。 若定义为决策函数的集合&#xff1a; F { f ∣ Y f ( X ) } \mathcal{F…

60.在 Vue 3 中使用 OpenLayers 绘制自由线段、自由多边形

前言 在现代 Web 开发中&#xff0c;地图功能已经成为许多应用的重要组成部分。OpenLayers 是一个强大的开源地图库&#xff0c;支持多种地图源和地图操作。结合 Vue 3 的响应式特性&#xff0c;我们可以轻松实现地图的交互功能。本文将详细介绍如何在 Vue 3 中使用 OpenLayer…

krpano 实现文字热点中的三角形和竖杆

krpano 实现文字热点中的三角形和竖杆 实现文字热点中的三角形和竖杆 一个后端写前端真的是脑阔疼 一个后端写前端真的是脑阔疼 一个后端写前端真的是脑阔疼 实现文字热点中的三角形和竖杆 上图看效果 v&#xff1a;2549789059

【算法】字符串算法技巧系列

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 引入&#xff1a;字符串相关算法技巧 1&#xff1a;字符串转数组 2&#xff1a;子字符串 3&#xff…