带你深入理解“栈”(c语言 c++和stl Stack三个版本的模拟实现)

news2024/12/17 6:55:55

目录

一.栈的概念及结构

二.栈的实现(c语言版)

2.1静态增长的栈

2.2动态增长的栈

2.3动态栈的模拟实现

   1.栈的初始化

  2.入栈

 3.出栈

4.获取栈顶元素

5.获取栈中有效数据个数

6.检查栈是否为空

7.栈的销毁

三.C++ 版本模拟实现栈

 1.C++版本的源代码

四.c语言版本的源代码

  4.1  头文件.h源码

  4.2 功能实现的.c文件

4.3测试代码test.c文件


一.栈的概念及结构

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

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

二.栈的实现(c语言版)

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小

2.1静态增长的栈

下面是定长的静态栈的结构,栈的内存空间是固定的,当我们栈中的数据很少时,可能会浪费空间,而数据量很大的时候,栈有可能占不下大量的数据,所以,在实际中一般不实用。

typedef int STDataType;
#define N 10
typedef struct Stack
{
STDataType _a[N];
int _top; // 栈顶
}Stack;

2.2动态增长的栈

下面是动态增长的栈,初始化的时候可以先给_a一个固定的小值,如何根据用户输入的数据自我进行扩容

typedef int STDataType;

typedef struct Stack
{
STDataType* _a;
int _top; // 栈顶
int _capacity; // 容量
}Stack;

2.3动态栈的模拟实现

   1.栈的初始化

  在这里我对“栈”的容量给予5,然后用malloc去堆上创建5个int字节大小的空间付给我们的数组,因为malloc有可能申请失败,所以我们用if去进行判断。

  top栈顶初始化为0,代表没有数据。

void StackInit(Stack* ps)
{
    ps->capacity = 5;
    ps->a = (Stack*)malloc(ps->capacity * sizeof(STDataType));
    if (ps->a == NULL)
    {
        perror("malloc");
        exit(-1);
    }
    ps->top = 0;
}

  2.入栈

入栈,栈里面插入数据,相当于数组进行尾插

首先,进行判断,top栈顶等于capacity容量的时候,代表我们栈里的内存满了,这里我们需要扩容,用realloc对数组进行扩容,现在我进行的二倍扩容

判断完成后 进行插入数据,在数组栈顶插入传入的数据 data

void StackPush(Stack* ps, STDataType data)
{
	//扩容
	if (ps->top == ps->capacity)
	{
		Stack * da = (Stack*)realloc(  ps->a  ,ps->capacity * 2 * sizeof(STDataType));
		if (da == NULL)
		{
			perror("realloc");
			exit(-1);
		}
		else
		{
			ps->a = da;
		}
		ps->capacity *= 2;
	}

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

 3.出栈

出栈,直接栈顶元素减一就好了,以后插入的数据会直接替换原先的数据,而top--后自己也访问不到top以后的数据

void StackPop(Stack* ps)
{
	ps->top--;
}

4.获取栈顶元素

获取栈顶元素,因为数组下标是从0开始的,所以返回的是栈顶元素-1;

STDataType StackTop(Stack* ps)
{
	return ps->a[ps->top-1];
}

5.获取栈中有效数据个数

有效的数据个数就是 栈顶,直接返回栈顶就好了

int StackSize(Stack* ps)
{
	return ps->top;
}

6.检查栈是否为空

c语言并不支持bool,需要我们引用头文件#include<stdbool.h>

判断栈顶是否为0,来判断栈里是否有数据

有返回true

无返回false

bool StackEmpty(Stack* ps)
{
	if (ps->top == 0)
		return true;
	else
		return false;
}

7.栈的销毁

栈的销毁,对容量和栈顶进行请0,然后用free函数释放我们使用malloc/realloc在堆上开辟的空间

void StackDestroy(Stack* ps)
{
	ps->capacity = 0;
	ps->top = 0;
	free(ps->a);
	ps->a = NULL;	
}

以上就是c语言版本的栈的模拟实现

三.C++ 版本模拟实现栈

考虑到学校有好多老师上课,虽然说得是用c语言实现,却用cpp进行操作,现在给大家更新cpp版本的栈的模拟实现,cpp版本的扩容使用的new,函数参数使用的&,可能有同学对指针使用不太熟悉,所以我们同意用&(引用)来实现,方便大家的理解,就不再详细的进行说明了,思路跟c语言实现的一样,只是c和cpp的语言差距有所不同。

 1.C++版本的源代码

#include<iostream>
using namespace std;

// 支持动态增长的栈
typedef int STDataType;
typedef struct Stack1
{
	STDataType* a;
	int top;		// 栈顶
	int capacity;  // 容量 
}Stack;

// 初始化栈 
void StackInit(Stack& ps)
{
	ps.capacity = 5;
	ps.a = new STDataType[ps.capacity * sizeof(STDataType)];
	ps.top = 0;
}
// 入栈 
void StackPush(Stack& ps, STDataType data)
{
	//扩容
	if (ps.top == ps.capacity)
	{
		STDataType* da = new STDataType[ps.capacity * 2 * sizeof(STDataType)];
		ps.a = da;
		ps.capacity *= 2;
	}
	ps.a[ps.top] = data;
	ps.top++;
}
// 出栈 
void StackPop(Stack& ps)
{
	ps.top--;
}
// 获取栈顶元素 
STDataType StackTop(const Stack& ps)
{
	return ps.a[ps.top - 1];
}
// 获取栈中有效元素个数 
int StackSize(const Stack& ps)
{
	return ps.top;
}
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
bool StackEmpty( const Stack& ps)
{
	if (ps.top == 0)
		return true;
	else
		return false;
}
// 销毁栈 
void StackDestroy(Stack& ps)
{
	ps.capacity = 0;
	ps.top = 0;
	delete ps.a;
	ps.a = NULL;
}


int main()
{
	Stack s;
	StackInit(s);

	StackPush(s, 1);
	StackPush(s, 2);
	StackPush(s, 3);
	StackPush(s, 4);

	for (int i = 0;i < 4;i++)
	{
		cout << StackTop(s) << endl;
		StackPop(s);
	}

	printf("栈中有效元素个数为 %d \n", StackSize(s));
	if (StackEmpty(s))
	{
		printf("为空\n");
	}
	else
	{
		printf("不为空\n");
	}

	StackDestroy(s);
}

四.c语言版本的源代码

  4.1  头文件.h源码

	#include<stdio.h>
	#include<stdlib.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 
	bool StackEmpty(Stack* ps);
	// 销毁栈 
	void StackDestroy(Stack* ps);

  4.2 功能实现的.c文件

#include"Stack.h"

// 初始化栈 
void StackInit(Stack* ps)
{
	assert(ps);
	ps->capacity = 5;
	ps->a = (Stack*)malloc(ps->capacity * sizeof(STDataType));
	if (ps->a == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	ps->top = 0;
}
// 入栈 
void StackPush(Stack* ps, STDataType data)
{
	assert(ps);
	//扩容
	if (ps->top == ps->capacity)
	{
		Stack * da = (Stack*)realloc(  ps->a  ,ps->capacity * 2 * sizeof(STDataType));
		if (da == NULL)
		{
			perror("realloc");
			exit(-1);
		}
		else
		{
			ps->a = da;
		}
		ps->capacity *= 2;
	}

	ps->a[ps->top] = data;
	ps->top++;
}
// 出栈 
void StackPop(Stack* ps)
{
	assert(ps);
	assert(ps->top > 0);
	ps->top--;
}
// 获取栈顶元素 
STDataType StackTop(Stack* ps)
{
	assert(ps);
	return ps->a[ps->top-1];
}
// 获取栈中有效元素个数 
int StackSize(Stack* ps)
{
	return ps->top;
}
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
bool StackEmpty(Stack* ps)
{
	if (ps->top == 0)
		return true;
	else
		return false;
}
// 销毁栈 
void StackDestroy(Stack* ps)
{
	assert(ps);

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

4.3测试代码test.c文件

#include"Stack.h"

int main()
{
	Stack s;
	StackInit(&s);

	StackPush(&s, 1);
	StackPush(&s, 2);
	StackPush(&s, 3);
	StackPush(&s, 4);

	StackPop(&s);

	printf("栈顶元素为%d \n", StackTop(&s));
	printf("栈中有效元素个数为 %d \n", StackSize(&s));

	if (StackEmpty(&s))
	{
		printf("为空\n");
	}
	else
	{
		printf("不为空\n");
	}

	StackDestroy(&s);


}

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

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

相关文章

java代理示例

以上代码通过Apache HttpComponents库&#xff0c;使用Java其中&#xff0c;proxy_host参数为代理服务器的主机名&#xff0c;proxy_port参数为服务器的端口号。程序首先创建了一个HttpGet对象&#xff0c;然后创建了一个HttpClient对象。接着&#xff0c;设置了HttpGet对象的U…

使用Typecho搭建个人博客网站,并内网穿透实现公网访问

使用Typecho搭建个人博客网站&#xff0c;并内网穿透实现公网访问 文章目录 使用Typecho搭建个人博客网站&#xff0c;并内网穿透实现公网访问前言1. 安装环境2. 下载Typecho3. 创建站点4. 访问Typecho5. 安装cpolar6. 远程访问Typecho7. 固定远程访问地址8. 配置typecho 前言 …

接口测试 —— Requests库GET请求!

Requests库GET请求是使用HTTP协议中的GET请求方式对目标网站发起请求。 &#xff08;不带参数的GET请求请看上一篇文章的练习&#xff09; 1、Requests库待参数的GET请求 使用Get方法带参数请求时&#xff0c;是params参数字典&#xff0c;而不是data参数字典。data参数字典…

亚马逊云科技Amazon Lightstail(VPS)与其他主流VPS相比优势在哪里?

亚马逊云科技作为全球网络科技的一方巨擘&#xff0c;在全球云计算领域可谓一枝独秀。而说到云计算领域&#xff0c;作为入门和基础使用场景的VPS就是一个无法绕开的话题。那么亚马逊云科技又有什么样的优势呢&#xff1f;今天这篇文章就市面现有的VPS服务做比较&#xff0c;解…

MYSQL数据库的概念和sql语句

数据是什么 数&#xff1a;数字信息 据&#xff1a;属性或某种凭据 数据&#xff1a;对一些列对对象的具体属性的描述信息的集合。 数据库是什么 数据库&#xff1a;就是用来组织 (按照规则组织起来的) &#xff0c;存储和管理 (对数据的增、删、改、查) 数据的仓库。 数…

【C++】set multiset

文章目录 前言1.set介绍2.set的使用3.multiset介绍4.multiset的使用 前言 知识铺垫&#xff1a;关联式容器和值键对概念 链接-【C】关联式容器 & 键值对&#xff08;概念介绍&#xff09; 1.set介绍 set文档 翻译&#xff1a; set是按照一定次序存储元素的容器&#xff…

2023年安全生产监管人员证考试题库及安全生产监管人员试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年安全生产监管人员证考试题库及安全生产监管人员试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作业人员上岗证考试…

typedef复杂函数接口的解释

文章目录 typedef定义函数解释interface.h接口1、函数定义2、函数实现加载动态链接库3、sdologinentry.dll或者sdologinentry64.dll动态链接库哪个工程生成的并导出三个接口函数4、sdologinsdk.dll或者sdologinsdk64.dll动态链接库哪个工程生成并导出三个接口函数 typedef定义函…

redis爆满导致数据丢失

记一则redis爆满导致数据丢失的一场事故 某功能上线后&#xff0c;发现出现问题&#xff0c;最后定位到了 redis. 由于存储的数据过多&#xff0c;导致阿里云4G大小的 redis 爆满&#xff0c;触发了回收策略。 于是临时扩容,运维同学当时未找到阿里云配置。 后面我用工具连接了…

微服务-Feign

文章目录 Feign介绍Feign的基本使用自定义Feign的配置Feign性能优化Feign最佳实践 Feign介绍 RestTemplate远程调用存在的问题&#xff1a;代码可读性差&#xff0c;java代码中夹杂url&#xff1b;参数复杂很难维护 String url "http://userservice/user/" order.g…

常见MySQL数据库无法启动的解决方案

前言&#xff1a; 数据库无法启动是在运维中常见的问题&#xff0c;大多是重启服务器、磁盘损坏、配置不当导致的。建议您在面板计划任务中做个数据库全部备份的计划任务&#xff0c;这样在遇到问题的情况下可以及时通过备份进行恢复。 在根据下面的案例尝试恢复或者启动数据库…

dedecms 文件上传(CVE-2019-8933)

dedecms 文件上传&#xff08;CVE-2019-8933&#xff09; 漏洞简介 远程攻击者可通过在添加新模板时&#xff0c;将文件名…/index.html更改成…/index.php利用该漏洞向uploads/目录上传.php文件并执行该文件。 后台路径&#xff1a;/uploads/dede/ 后台密码&#xff1a;admi…

贪心算法学习——最大数

目录 ​编辑 一&#xff0c;题目 二&#xff0c;题目接口 三&#xff0c;解题思路级代码 一&#xff0c;题目 给定一组非负整数 nums&#xff0c;重新排列每个数的顺序&#xff08;每个数不可拆分&#xff09;使之组成一个最大的整数。 注意&#xff1a;输出结果可能非常大…

WEB使用百度地图展示某地地址

第一步 进入百度地图开发平台 百度地图开放平台 | 百度地图API SDK | 地图开发 第二步注册 获取AK秘钥&#xff0c;点击【创建应用】进入AK申请页面&#xff0c;填写应用名称&#xff0c;务必选择AK类型为“浏览器端”&#xff0c;JS API只支持浏览器端AK进行请求与访问 下面…

AVM赛道研究:预计2024年渗透率突破50%!下一个破局点在哪儿?

作为一个典型的基础智能化细分赛道&#xff0c;全景环视&#xff08;AVM&#xff09;的发展历程值得市场借鉴。 这其中的原因包括&#xff0c;①对比渗透率仍处低位的高阶智驾&#xff0c;单一AVM赛道的产品基本进入成熟期&#xff08;渗透率继续高歌猛进&#xff09;&#xf…

《算法通关村—如何基于数组(或者链表)实现栈》

《算法通关村—如何基于数组&#xff08;或者链表&#xff09;实现栈》 理解什么是栈 栈和队列是比较特殊的线性表&#xff0c;又称之为访问受限的线性表。栈是很多表达式、符号等运算的基础&#xff0c;也是递归的底层实现。理论上递归能做的题目栈都可以&#xff0c;只是有…

NLog详解

目录 1.简介 2.项目中使用NLog 2.1 快速使用NLog 2.2 通过配置文件使用NLog 3.NLog配置参数详解 3.1 全局配置 3.2 根元素 3.2.1 targets 3.2.1.1 layout 3.2.2 rules 3.2.3 extensions 3.2.4 include 3.2.5 variable 4.附录 1.简介 NLog是一个基于.NET平台编写…

【C++代码】分糖,分饼干,摇摆序列,贪心算法--代码随想录

贪心的本质是选择每一阶段的局部最优&#xff0c;从而达到全局最优。靠自己手动模拟&#xff0c;如果模拟可行&#xff0c;就可以试一试贪心策略&#xff0c;如果不可行&#xff0c;可能需要动态规划。贪心算法一般分为如下四步&#xff1a; 将问题分解为若干个子问题找出适合的…

Shell 邮件发送告警测试

1.先编辑mail配置文件 #cat /etc/mail.rc#开启ssl set ssl-verifyignore#证书目录&#xff0c;下方为centos系统证书默认位置&#xff0c;也自行生成证书并指定 set nss-config-dir/etc/pki/nssdb# 配置的第三方smtp服务器的地址及端口 set smtpsmtps://smtp.163.com:465 # 认…

<多线程章节二>创建线程的几种常见方式

文章专栏 本篇文章收录于多线程&#xff0c;也欢迎翻阅博主的其他文章&#xff0c;可能也会让你有不一样的收获&#x1f604; &#x1f4a1;JavaSE语法 &#x1f4a1;数据结构 &#x1f4a1;多线程 &#x1f4a1;专栏导读 操作系统提供了一些API来操作线程&#xff0c;Java针对…