【数据结构】使用C语言 从零实现一个栈的数据结构

什么是栈?栈是一种特殊的线性表,它只能在在表尾进行插入和删除操作。

栈的底部称为栈底,顶部称为栈顶,所有的操作只能在栈顶进行,也就是说,被压在下方的元素,只能等待其上方的元素出栈之后才能取出,就像我们往箱子里里面放的书一样,因为只有一个口取出里面的物品,所以被压在下面的书只能等上面的书被拿出来之后才能取出,这就是栈的思想,它是一种先进后出的数据结构。

使用C语言实现栈

一般使用栈这样的机构,常用的两个操作就是入栈和出栈

  • pop:出栈操作,将栈顶的元素取出,并删除
  • push:入栈操作,将新元素置入栈顶

定义数据结构

我们在栈的底层使用数组进行存储,所以结构中将储存一个数组的指针,和数组的容量(方便初始化和申请内存);另外栈只能操作栈顶的元素,所以结构中还存着一个变量top,表示栈顶的元素。

typedef int E;struct Stack
{E * array; // 一个数组的指针int capacity; // 数组的容量int top;  // 栈顶的元素
};typedef struct Stack * stack;

再给栈结构的指针起一个别名,便于后续对栈进行操作。

定义初始化方法

接着我们定义一个初始化栈的方法,在初始化方法中,我们默认初始化时,底层数组的最大容量是10个内存单位,也就是40字节(因为E是int类型),接着我们定义,刚初始化完栈之后是一个空栈,则栈顶的指针默认为-1。

top变量是为后续的入栈出栈操作做铺垫的,它可以当作数组的索引,也可以用来当作是否是空栈的标识。

int initStack(stack stack)
{stack->array = malloc(sizeof(E) * 10); // 申请一个40字节的内存if (stack->array == NULL) return 0;stack->capacity = 10; // 记录底层数组的容量stack->top = -1;  // 栈没有元素默认为-1return 1;
}

在main函数中,实例化一个Stack类型,接着使用initStack函数就完成了栈的初始化:

int main()
{struct Stack stack;initStack(&stack);return 0;
}

实现入栈操作

入栈操作,就是把一个元素放到栈的最上方,也就是栈顶上,所以实现该操作的函数只需要有两个参数就可以了:

  • 栈的指针
  • 需要入栈的元素

另外,底层数组的默认容量是10,如果入栈超过10个元素的话,内存就会造成泄露,所以对底层数组进行扩容操作也是必不可少的。

int pushStack(stack stack,E element)
{if (stack->top == stack->capacity - 1) // 扩容{int newCapacity = stack->capacity * 2;E* newArray = realloc(stack->array,newCapacity * sizeof(E));if (newArray == NULL) return 0;stack->array = newArray;stack->capacity = newCapacity;}stack->top++;stack->array[stack->top] = element;return 1;
}

在扩容操作中,我们使用realloc函数将原数组拷贝到一个新的大小的内存中,这个内存地址我们使用newArray来接收,最后将原栈中的array指向newArray,将原栈中的capacity 指向newCapacity

简单编写一个打印栈元素的函数,用于测试栈:

void printStack(stack stack)
{printf("|");for (int i = 0;i<=stack->top;i++){printf("%d, ",stack->array[i]);}printf("\n");
}int main()
{struct Stack stack;initStack(&stack);for(int i = 1;i<=10;i++){pushStack(&stack,i);}printStack(&stack);return 0;
}

控制台输出:

|1, 2, 3, 4, 5, 6, 7, 8, 9, 10,

入栈操作成功实现~

实现出栈操作

出栈操作就是把栈顶的元素取出,然后把top执行自减操作,如果不自减元素出栈之后栈顶的元素还会是原来的元素。

E popStack(stack stack)
{if (stack->top == -1){printf("栈为空,不能出栈\n");return -1;}E element = stack->array[stack->top];stack->top--;return element;
}

我们接着测试一下:

void printStack(stack stack)
{printf("|");for (int i = 0;i<=stack->top;i++){printf("%d, ",stack->array[i]);}printf("\n");
}int main()
{struct Stack stack;initStack(&stack);for(int i = 1;i<=20;i++){pushStack(&stack,i);}printStack(&stack);printf("出栈的元素顺序:");while (1){printf("%d, ",stack.array[stack.top]);popStack(&stack);if (stack.top == -1) break;}return 0;
}

会发现控制台输出的信息为:

|1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
出栈的元素顺序:20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,

出栈的顺序是从20到1的,说明元素是从栈顶依次出去的,至此出栈操作也实现好了。

总结

使用C语言手动把栈的结构和各种操作实现一遍是很重要的,它能够加深学习者对计算机底层的认识,也能够为后续的算法题的解题提供一种新的思路。

本篇博文所有代码:

#include "stdio.h"
#include "stdlib.h"typedef int E;struct Stack
{E * array; // 一个数组的指针int capacity; // 数组的容量int top;  // 栈顶的元素
};typedef struct Stack * stack;int initStack(stack stack)
{stack->array = malloc(sizeof(E) * 10); // 申请一个40字节的内存if (stack->array == NULL) return 0;stack->capacity = 10; // 记录底层数组的容量stack->top = -1;  // 栈没有元素默认为-1return 1;
}int pushStack(stack stack,E element)
{if (stack->top == stack->capacity - 1) // 扩容{int newCapacity = stack->capacity * 2;E* newArray = realloc(stack->array,newCapacity * sizeof(E));if (newArray == NULL) return 0;stack->array = newArray;stack->capacity = newCapacity;}stack->top++;stack->array[stack->top] = element;return 1;
}E popStack(stack stack)
{if (stack->top == -1){printf("栈为空,不能出栈\n");return -1;}E element = stack->array[stack->top];stack->top--;return element;
}void printStack(stack stack)
{printf("|");for (int i = 0;i<=stack->top;i++){printf("%d, ",stack->array[i]);}printf("\n");
}int main()
{struct Stack stack;initStack(&stack);for(int i = 1;i<=20;i++){pushStack(&stack,i);}printStack(&stack);printf("出栈的元素顺序:");while (1){printf("%d, ",stack.array[stack.top]);popStack(&stack);if (stack.top == -1) break;}return 0;
}

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

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

相关文章

LeetCode-简单-回文数

给你一个整数 x &#xff0c;如果 x 是一个回文整数&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 回文数 是指正序&#xff08;从左向右&#xff09;和倒序&#xff08;从右向左&#xff09;读都是一样的整数。 例如&#xff0c;121 是回文&#xff0c;…

windows启动Docker闪退Docker desktop stopped

Windows启动Docker闪退-Docker desktop stopped 电脑上很早就安装有Docker了&#xff0c;但是有一段时间都没有启动了&#xff0c;今天想启动启动不起来了&#xff0c;打开没几秒就闪退&#xff0c;记录一下解决方案。仅供参考 首先&#xff0c;参照其他解决方案&#xff0c;本…

Ubuntu20安装mysql方法,适用于wsl

itopen组织1、提供OpenHarmony优雅实用的小工具2、手把手适配riscv qemu linux的三方库移植3、未来计划riscv qemu ohos的三方库移植 小程序开发4、一切拥抱开源&#xff0c;拥抱国产化 一、Ubunt20安装mysql 适用于wsl中安装mysql sudo apt update# 查看可使用的安装包…

【刷题汇总--游游的you、腐烂的苹果、孩子们的游戏(圆圈中最后剩下的数)】

C日常刷题积累 今日刷题汇总 - day0051、游游的you1.1、题目1.2、思路1.3、程序实现 - 蛮力法1.4、程序实现 - 贪心(优化) 2、腐烂的苹果2.1、题目2.2、思路2.3、程序实现 - bfs 3、孩子们的游戏(圆圈中最后剩下的数)3.1、题目3.2、思路3.3、程序实现 -- 环形链表3.4、程序实现…

2个方法教你轻松移除pdf文件编辑限制

PDF是一种常见的办公文档格式&#xff0c;常用于文件共享和保护。然而&#xff0c;有时候我们需要编辑PDF文件中的内容&#xff0c;但受到了编辑限制。本文将介绍一些有效的方法&#xff0c;帮助您解除PDF的编辑限制&#xff0c;轻松进行编辑和修改。 一、通过密码取消PDF“限制…

雷电模拟器报错remount of the / superblock failed: Permission denied remount failed

报错截图 解决方法 打开设置 设置配置system.vmdk可写入 解决

Transformer和Mamba强强结合!最新混合架构全面开源,推理速度狂飙8倍

最近发现&#xff0c;将Mamba和Transformer模块混合使用&#xff0c;效果会比单独使用好很多&#xff0c;这是因为该方法结合了Mamba的长序列处理能力和Transformer的建模能力&#xff0c;可以显著提升计算效率和模型性能。 典型案例如大名鼎鼎的Jamba&#xff1a;Jamba利用Tr…

ELK优化之Elasticsearch

目录 1.ELK优化 2.优化 ES 索引设置 2.1 优化 fsync 2.2 优化 refresh 2.3 优化 merge 2.4 优化设置 2.5 打开索引 3.优化线程池配置 3.1 优化的方案 4.锁定内存&#xff0c;不让 JVM 使用 Swap 5.减少分片数、副本数 6.ES优化总结 1.ELK优化 ELK优化可以围绕着 li…

Python统计实战:时间序列分析之简单指数平滑和Holt指数平滑

为了解决特定问题而进行的学习是提高效率的最佳途径。这种方法能够使我们专注于最相关的知识和技能&#xff0c;从而更快地掌握解决问题所需的能力。 &#xff08;以下练习题来源于《统计学—基于Python》。请在Q群455547227下载原始数据。&#xff09; 练习题 下表是某只股票…

二维平面无中心点的聚类算法

问题描述 二维平面上有许多点p(x , y)&#xff0c;按照彼此之间的欧式距离进行分为若干个集合。若点p1(x1, y1)与点p(x2, y2)之间距离小于d,则认为二者是邻居。 算法思路 给数据集的点进行编号&#xff0c;顺序遍历这些点&#xff0c;找出当前点的邻居&#xff0c;记住已经遍…

模具监视器的选择要点介绍

模具监视器的选择要点涉及多个方面&#xff0c;以确保其能够满足实际生产需求并提高生产效率。以下是一些关键的选择要点&#xff1a; 一、性能和稳定性 监控精度&#xff1a;选择模具监视器时&#xff0c;首先要考虑其监控精度&#xff0c;包括温度、压力、注射速度等参数的…

Debezium系列之:JVM参数详解和Debezium集群JVM监控看板制作

Debezium系列之:JVM参数详解和Debezium集群JVM监控看板制作 一、JVM参数详解1.jvm_memory_bytes_used2.jvm_memory_bytes_committed3.jvm_memory_bytes_max4.jvm_memory_bytes_init5.jvm_memory_pool_bytes_used6.jvm_memory_pool_bytes_committed7.jvm_memory_pool_bytes_max…

金属3D打印如何精准选材

随着3D打印技术的飞跃发展&#xff0c;模具制造领域迎来了前所未有的创新机遇。在众多3D打印技术中&#xff0c;SLM金属3D打印以其精度高、复杂结构成型能力&#xff0c;成为众多行业的优选。然而&#xff0c;金属打印材料&#xff0c;如何精准选择&#xff0c;以最大化满足项目…

linux 内核打印log太多咋办?

有时候发现&#xff0c;linux 内核打印太多消息了&#xff0c;对有用消息造成了干扰&#xff0c;如果你一个个源文件去关闭打印太麻烦了&#xff0c;有没有一种更方便的方式来关闭这些消息呢&#xff1f; 对这个需求&#xff0c;内核提供了一个强大而又灵活的方式&#xff0c;…

开源 WAF 解析:选择最适合你的防护利器

前言 随着网络安全风险的增加&#xff0c;Web 应用防火墙&#xff08;WAF&#xff09;成为保护网站和应用程序免受攻击的关键工具。在众多的选择中&#xff0c;开源 WAF 以其灵活性、可定制性和成本效益备受青睐。本文将深入探讨几种主流开源 WAF 解决方案&#xff0c;帮助你选…

用html+css设计一个列表清单小卡片

目录 简介: 效果图: 源代码: 可能的问题: 简介: 这个HTML代码片段是一个简单的列表清单设计。它包含一个卡片元素(class为"card"),内部包含一个无序列表(ul),列表项(li)前面有一个特殊的符号(△)。整个卡片元素设计成300px宽,150px高,具有圆角边…

从0-1配置一个ROS项目

目标&#xff1a;从0-1配置一个ROS项目&#xff0c;实现hello,world打印&#xff0c;在此基础上进行功能开发。 步骤1&#xff1a;创建工作空间&#xff1a; mkdir -p ros_workspace/src cd ros_workspace对工作空间进行初始化&#xff1a; catkin_make source devel/setup.…

20.【C语言】初识结构体(重要)

定义&#xff1a;由一批数据组合而成的结构型数据 作用&#xff1a;描述复杂对象&#xff0c;创建新的类型 格式&#xff1a; struct 对象 { …… } 介绍. 用法&#xff1a;结构体变量.成员变量 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> struct hotal…

代码随想录训练营Day57

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、X的平方根二、有效的完全平方数 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 今天是跟着代码随想录刷题的第57天&#xff0c;继…

Prompt-Free Diffusion: Taking “Text” out of Text-to-Image Diffusion Models

CVPR2024 SHI Labshttps://arxiv.org/pdf/2305.16223https://github.com/SHI-Labs/Prompt-Free-Diffusion 问题引入 在SD模型的基础之上&#xff0c;去掉text prompt&#xff0c;使用reference image作为生成图片语义的指导&#xff0c;optional structure image作为生成图片…