C数据结构:栈

news2025/1/16 8:14:14

目录

栈的作用

栈的实现

栈的数据结构

栈的初始化

栈的销毁

栈的插入

栈的删除

获得栈顶元素

获得栈有效元素个数

判断栈是否为空

栈的使用

完整代码


栈是一种特殊结构的线性表

先来看看栈的图

之所以说它特殊,是因为它的插入删除功能比较特殊

栈的插入也叫作压栈/入栈/进栈

栈的插入只能在栈顶插入

栈的删除也叫作出栈

栈的删除只能在栈顶删除

栈的作用

栈这种特殊的结构可以让我们在解决特定问题的时候会有很大的帮助

类似的例如队列也是

这也是我们学习多种数据结构的原因

栈的实现

我们要实现的栈是能够动态扩容的栈,而不是静态栈

栈可以使用两种数据结构实现,一种是顺序表,一种是链表,这里是通过顺序表为底层实现的

因为静态在现实中并不常用,缺点也很明显(容易浪费空间或者空间不足)

下面先来看看栈的数据结构

栈的数据结构

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

结构体里有三个成员

1、_a是指向一块连续空间的指针

2、_top是栈顶(主要用于入栈出栈)

3、_capacity是栈的容量(便于后续调整_a指针指向的空间的大小)

栈的初始化

void StackInit(Stack* ps)
{
	assert(ps);

	ps->_a = NULL;
	ps->_capacity = 0;
	ps->_top = 0;
}

这里初始化暂时先让_a指针为NULL

所以capacity容量当然为0

也可以选择先malloc一块空间,先让_a指针指向它,后续再扩容,但capacity也要跟着一起改 

这里top的初始化就比较有争议了

top刚开始可以为0,也可以刚开始为-1

若top刚开始为0,则top表示栈顶数据的最后一个元素的下一个元素的下标,也可以表示栈的大小(size)

若top刚开始为-1,则top表示最后有效数据的下标(例如栈中有3个数据,那么top为3,top则为最后一个数据的下标)

这里我们选择了top=0,则下面写的代码也是为top=0而准备的

栈的销毁

void StackDestroy(Stack* ps)
{
	assert(ps);

	free(ps->_a);
	ps->_a = NULL;
	ps->_capacity = 0;
	ps->_top = 0;
}

销毁只需要释放掉_a指针指向的空间,并设为NULL,capacity、top=0即可 

栈的插入

void StackPush(Stack* ps, STDataType data)
{
	assert(ps);

	if (ps->_capacity == ps->_top)
	{
		int newcapacity = ps->_capacity == 0 ? 4 : ps->_capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->_a, sizeof(STDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail\n");
			return;
		}
		ps->_a = tmp;
		ps->_capacity = newcapacity;
	}
	ps->_a[ps->_top] = data;
	ps->_top++;
}

因为我们要插入数据,那么插入数据之前我们要先判断_a指针所指向的空间还是否有剩余,判断条件就是capacity = top,若条件满足则表示空间不足,则需要扩容

第一个newcapacity用了一个三目操作符,若刚开始的空间为0,则初始化newcapacity为4,否则newcapacity = capacity * 2

然后使用了一个tmp指针接收我们realloc函数的返回值,并为_a空间扩容

这里若_a = NULL,则realloc会当作malloc先开辟一块空间,并让tmp指向这块空间,所以到后面我们需要让_a = tmp

若tmp = NULL,则代表realloc扩容失败,perror函数打印错误信息,并return

不若则扩容成功,当_a获取到新的空间后我们直接在栈顶的位置插入data即可

最后让top++往后走

栈的删除

void StackPop(Stack* ps)
{
	assert(ps);
	assert(ps->_top > 0);

	ps->_top--;
}

删除只需要让top--即可(注意断言防止top越界)

为什么我们要单独写一个函数调用来让top--而不是在主函数中直接让top--?

因为若是别人使用我们实现的栈,别人并不知道我们的top的含义是什么

也就是我们刚开始讲的top初始化为0和top初始化为-1的区别 

获得栈顶元素

STDataType StackTop(Stack* ps)
{
	assert(ps);
	assert(ps->_top > 0);

	return ps->_a[ps->_top - 1];
}

直接返回top-1位置的值即可 

获得栈有效元素个数

int StackSize(Stack* ps)
{
	assert(ps);

	return ps->_top;
}

前面也写了有效元素的个数即为top

所以直接返回top即可 

判断栈是否为空

int StackEmpty(Stack* ps)
{
	assert(ps);

	return ps->_top == 0;
}

若top为0则代表empty为空

栈的使用

int main()
{
    Stack st;
    StackInit(&st);
    StackPush(&st, 1);
    StackPush(&st, 2);
    StackPush(&st, 3);
    StackPush(&st, 4);
    while (!StackEmpty(&st))
    {
    	int tmp = StackTop(&st);
    	StackPop(&st);
    	printf("%d ", tmp);
    }
    StackDestroy(&st);
}

首先我们向栈中入了四个元素,1,2,3,4

若我们要将它们全部打印出来只能向上面一样写个循环

先判断若栈不为空,则循环继续

先保存栈顶元素到tmp中

将栈顶元素删除(这样才能取到下一个元素)

然后打印我们刚刚取到的栈顶元素(也就是刚刚删除掉的元素)

最后别忘了将栈销毁,防止内存泄漏

完整代码

Stack.h

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <assert.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->_capacity = 0;
	ps->_top = 0;
}
 
void StackPush(Stack* ps, STDataType data)
{
	assert(ps);

	if (ps->_capacity == ps->_top)
	{
		int newcapacity = ps->_capacity == 0 ? 4 : ps->_capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->_a, sizeof(STDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail\n");
			return;
		}
		ps->_a = tmp;
		ps->_capacity = newcapacity;
	}
	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);
	assert(ps->_top > 0);

	return ps->_a[ps->_top - 1];
}

int StackSize(Stack* ps)
{
	assert(ps);

	return ps->_top;
}

int StackEmpty(Stack* ps)
{
	assert(ps);

	return ps->_top == 0;
}

void StackDestroy(Stack* ps)
{
	assert(ps);

	free(ps->_a);
	ps->_a = NULL;
	ps->_capacity = 0;
	ps->_top = 0;
}

Test.c

#include "Stack.h"

void TestStack()
{
	Stack st;
	StackInit(&st);
	StackPush(&st, 1);
	StackPush(&st, 2);
	StackPush(&st, 3);
	StackPush(&st, 4);
	while (!StackEmpty(&st))
	{
		int tmp = StackTop(&st);
		StackPop(&st);
		printf("%d ", tmp);
	}
	StackDestroy(&st);
}

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

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

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

相关文章

DBdoctor产品介绍

基本信息 DBdoctor是聚好看科技股份有限公司自主研发的一款数据库内核级性能诊断工具&#xff0c;首次将eBPF技术聚焦在了数据库领域&#xff0c;一分钟内定位数据库性能问题并给出优化建议&#xff0c;实现数据库性能诊断百倍提效。 免费下载 请在PC端打开以下链接&#x…

Burp Suite抓取明文

目录 Burp Suite代理 正常的通信模式 Burp Suite代理后通信模式 设置代理 安装证书 导出证书 Burp Suite导入 浏览器下载证书 安装证书 管理证书 导入证书 下一步 导入证书 下一步 完成 抓明文的例子 1、修改浏览器代理 ​编辑2、开启拦截​编辑 3、查看抓取历…

NSS题目练习

[SWPUCTF 2021 新生赛]gift_F12 通过题目提示可以知道flag应该可以在源代码中找到 查看源代码&#xff0c;直接用 ctrlf 搜索flag即可 [SWPUCTF 2021 新生赛]jicao 题目打开后能看到一串php代码&#xff0c;要求是用post传参传入idwllmNB以及用get传参传入json[x]"wllm&q…

YoloV5的学习与使用

前言 Yolo算法简介 YOLO (You Only Look Once) 是一种用于目标检测的深度学习算法&#xff0c;由 Joseph Redmon、Santosh Divvala、Ross Girshick 和 Ali Farhadi 在 2015 年提出。YOLO 是一种端到端的算法&#xff0c;它将目标检测任务视为一个单一的回归问题&#xff0c;从…

Web3钱包开发获取测试币-OKB X1Testnet(三)

Web3钱包开发获取测试币-OKB X1Testnet(三) 基于以上两篇 Web3钱包开发获取测试币-Polygon Mumbai(一) &#xff1a;https://suwu150.blog.csdn.net/article/details/137949473Web3钱包开发获取测试币-Base Sepolia(二)&#xff1a;https://suwu150.blog.csdn.net/article/det…

【HTTP下】总结{重定向/cookie/setsockopt/流操作/访问网页/总结}

文章目录 1.请求头2.cookie理解 3.vim跳转/搜索4.setsockopt被重用的意思 5.流操作5.1定位读取指针5.2ifstram::read() 6.总结6.1 百度搜索框搜索功能字符6.2请求uri请求和响应的第一行都有http版本请求内容里有GET /favicon.ico HTTP/1.1 6.3访问网页Fiddler抓包原理&#xff…

从零开始的软件测试学习之旅(九)jmeter直连数据库及jmeter断言,关联

jmeter直连数据库及断言,关联 jmeter直连数据库步骤jmeter断言jmeter逻辑控制器if控制器ForEach控制器循环控制器 Jmeter关联Jmeter关联XPath提取器Jmeter关联正则表达式提取器二者比较跨线程组关联 每日复习 jmeter直连数据库 概念 这不叫直连:Jmeter -> java/python 提供的…

W801学习笔记二十四:NES模拟器游戏

之前已经实现了NES模拟器玩游戏。W801学习笔记九&#xff1a;HLK-W801制作学习机/NES游戏机(模拟器) 现在要在新版本掌机中移植过来。 1、把NES文件都拷贝到SD卡中。 这回不会受内存大小限制了。我这里拷贝了4个&#xff0c;还可以拷贝更多。 2、应用初始化中&#xff0c;加载…

Spring:OAuth2.0

文章目录 一、认证与授权二、OAuth2.0介绍 一、认证与授权 认证&#xff08;Authentication&#xff09;与授权&#xff08;Authorization&#xff09;在网络安全和系统管理中是两个重要的概念&#xff0c;它们各自有不同的作用和目标。 认证是验证确认身份以授予对系统的访问…

编辑员工信息——后端

需求&#xff1a; 在员工管理列表页面点击编辑按钮&#xff0c;跳转到编辑页面&#xff0c;在编辑页面回显员工信息并进行修改&#xff0c;最后点击保存按钮完成编辑操作。 代码开发流程&#xff1a; 点击编辑按钮&#xff0c;页面跳转到add.html&#xff0c;并在url中携带参…

高精度数学计算的瑞士军刀,mpmath库详解与应用示例

写在前言 hello&#xff0c;大家好&#xff0c;我是一点&#xff0c;专注于Python编程&#xff0c;如果你也对感Python感兴趣&#xff0c;欢迎关注交流。 做为一个一只脚已经踏进35岁大关的程序员&#xff0c;对于职场&#xff0c;几乎向上无望&#xff0c;已经没有太多的期待…

面向侧扫声纳目标检测的YOLOX-ViT知识精馏

面向侧扫声纳目标检测的YOLOX-ViT知识精馏 摘要IntroductionRelated WorkYOLOv-ViTKnowledge DistillationExperimental Evaluation Knowledge Distillation in YOLOX-ViT for Side-Scan Sonar Object Detection 摘要 在本文中&#xff0c;作者提出了YOLOX-ViT这一新型目标检测…

Springboot+vue项目零食销售商城

摘要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;零食销售商城当然也不能排除在外。零食销售商城是以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#xff…

Yolov8实现loopy视频识别

1、前言 loopy是一个非常可爱的动漫角色&#xff08;可爱粉色淀粉肠&#xff09;&#xff0c;闲来无事&#xff0c;打算用yolov8训练一个模型对loopy进行识别。 2、准备工作 先在网络上搜寻很多loopy的图片&#xff0c;然后将图片导入Lablel Studio软件进行标注&#xff0c;并…

Ansible---inventory 主机清单

一、inventory 主机清单 1.1、inventory介绍 hosts配置文件位置&#xff1a;/etc/ansible/hosts Inventory支持对主机进行分组&#xff0c;每个组内可以定义多个主机&#xff0c;每个主机都可以定义在任何一个或多个主机组内。 1.2、inventory中的变量 Inventory变量名含义…

Service 和 Ingress

文章目录 Service 和 IngressServiceEndpointservice 的定义代理集群外部服务反向代理外部域名Service 常用类型 IngressIngress-nginx安装使用 Service 和 Ingress service 和 ingress 是kubernetes 中用来转发网络请求的两个服务&#xff0c;两个服务用处不同&#xff0c;se…

python魔法方法是什么

魔法方法是python内置方法&#xff0c;不需要主动调用&#xff0c;存在的目的是为了给python的解释器进行调用&#xff0c;几乎每个魔法方法都有一个对应的内置函数&#xff0c;或者运算符&#xff0c;当我们对这个对象使用这些函数或者运算符时就会调用类中的对应魔法方法&…

【软考】模拟考卷错题本2024-05-07

1 项目路径 这里的图没有加载出来&#xff0c;没u哦i关系了。其实主要是的算出最长的路径中包含那些元素即可。这里是蒙圈了&#xff0c;没有考虑到还有更长的。要顾头也顾尾。 2 算法分析-贪心 该问题主要考核的是算法设计策略来达到目标的方式。主要的设计策略有&#xff1a;…

python实现图书馆借阅管理系统-文件存储

《面向对象》案例引入 通过本章的学习,请用面向对象思想实现《图书馆借阅管理系统》的登录注册页面和用户信息维护页面和图书借阅页面。 【功能要求】: 1、用面向对象思想改写上一章的《函数模块》案例引入。 2、增加图书借阅页面。 ①学生登录后,可以进入图书借阅页面,实现…

【自动驾驶|毫米波雷达】卡尔曼滤波

目录 一. 滤波器分类 二.卡尔曼滤波&#xff08;Kalman Filter&#xff09;原理 &#xff08;1&#xff09;定性理解 &#xff08;2&#xff09;定量推导 1. 预测阶段 2. 更新阶段 3. 卡尔曼增益 1&#xff09;卡尔曼增益 2&#xff09;如何理解卡尔曼增益&#xff1f; 三…