如何自己实现一个栈

文章转自编程珠玑,作者:守望先生

前言

栈是一种应用广泛的数据结构,例如函数的调用就需要使用栈,其实我们在介绍《

栈的操作

栈的常见操作有出栈(POP),从栈中弹出一个元素;入栈(PUSH),将一个元素压入栈中,访问栈顶元素(TOP),判断栈是否为空等。

栈的实现

栈是较容易实现的抽象数据结构之一。我们可以选择数组或者链表来实现,它们各有特点,前者容量有限且固定,但操作简单,而后者容量理论上不受限,但是操作并不如数组方便,每次入栈要进行内存申请,出栈要释放内存,稍有不慎便造成内存泄露。本文对两种实现都做介绍。

数组实现栈

用数组实现栈是比较容易的。这个时候的栈其实更像是访问受限的数组,数组可以通过下标访问,查找,插入等,但是栈只能从栈顶,或者说数组的末尾进行操作。我们只需要一个指针记录栈顶即可。有人可能问了,既然这里栈是访问受限的数组,为什么不直接使用数组呢?所谓能力越大,责任越大,而你暴露的越多,风险也越大就是如此。

我们来看一下数组实现栈的时候,栈的操作都是怎么实现的呢?

定义栈

用数组实现栈时是很容易定义的,只要定一个固定长度的数组即可,然后使用一个指针或者数组下标标记栈顶(topOfStack),栈为空时,它是-1:

#define STACK_SIZE 64 /*栈大小*/
#define TOP_OF_STACK -1 /*栈顶位置*/
typedef int ElementType /*栈元素类型*/
typedef struct StackInfo
{int topOfStack; /*记录栈顶位置*/ElementType stack[STACK_SIZE]; /*栈数组,也可以使用动态数组实现*/
}StackInfo_st;/*创建栈*/
StackInfo_st stack;
stack.topOfStack = TOP_OF_STACK;

入栈

入栈操作也很简单,只需要先将topOfStack加1,然后将元素放入数组即可。当然特别要注意检查此时栈是否已满。







将1入栈,此时topOfStack = 0,

topOfStack

1

代码实现:

#define SUCCESS 0
#define FAILURE -1
/*入栈,0表示成功,非0表示出错*/
int stack_push(StackInfo_st *s, ElementType value)
{if(stack_is_full(s))return FAILURE;/*先增加topOfStack,再赋值*/s->topOfStack++;s->stack[s->topOfStack] = value;return SUCCESS;
}

出栈或访问栈顶元素

与入栈相反,先访问元素,然后将topOfStack减1,但是此时要注意检查栈是否已空。访问栈顶元素可直接使用下标访问,而不用将topOfStack减1。

/*出栈*/
int stack_pop(StackInfo_st *s,ElementType *value)
{/*首先判断栈是否为空*/if(stack_is_empty(s))return FAILURE;*value = s->stack[s->topOfStack];s->topOfStack--;return SUCCESS;
}
/*访问栈顶元素*/
int stack_top(StackInfo_st *s,ElementType *value);
{/*首先判断栈是否为空*/if(stack_is_empty(s))return FAILURE;*value = s->stack[s->topOfStack];return SUCCESS;
}

判断栈是否满

只要判断topOfStack与数组大小-1的大小即可。

/*判断栈是否已满,满返回1,未满返回0*/
int stack_is_full(StackInfo_st *s)
{return s->topOfStack == STACK_SIZE - 1;
}

判断栈是否为空

只需要判断topOfStack是否小于等于-1即可。

/*判断栈是否为空,空返回1,非空返回0*/
int stack_is_empty(StackInfo_st *s)
{return s->topOfStack ==  - 1;
}

完整可运行代码

代码较长,可点击阅读原文查看或访问:

链表实现栈

与数组实现栈不一样的地方是,链式栈可以动态扩容,基本没有长度限制(受限于内存)。另外,它在入栈以及出栈的时候需要申请或者释放内存。

创建栈

创建栈很容易,只需要声明一个头指针即可,它的next指针指向栈顶,初始时为空:

/*定义栈结构*/
typedef struct StackInfo
{ElementType value; /*记录栈顶位置*/struct StackInfo *next; /*指向栈的下一个元素*/
}StackInfo_st;/*创建栈,外部释放内存*/
StackInfo_st *createStack(void)
{StackInfo_st *stack = malloc(sizeof(StackInfo_st));if(NULL == stack){printf("malloc failed\n");return NULL;} /*stack-next为栈顶指针*/stack->next = NULL;return stack;
}

入栈

入栈只需要为新的元素申请内存空间,并将栈顶指针指向新的节点即可。

640?wx_fmt=png
入栈操作
/*入栈,0表示成功,非0表示出错*/
int stack_push(StackInfo_st *s,ElementType value)
{StackInfo_st *temp = malloc(sizeof(StackInfo_st));if(NULL == temp){printf("malloc failed\n");return FAILURE;}/*将新的节点添加s->next前,使得s->next永远指向栈顶*/temp->value = value;temp->next = s->next;s->next = temp;return SUCCESS;
}

出栈或访问栈顶元素

出栈时,将栈顶指针指向下下个节点,返回元素值,并释放栈顶指针下个节点的内存。而访问栈顶元素只需要返回栈顶指针指向节点的元素值即可。

640?wx_fmt=png
出栈
/*出栈*/
int stack_pop(StackInfo_st *s,ElementType *value)
{/*首先判断栈是否为空*/if(stack_is_empty(s))return FAILURE;/*找出栈顶元素*/*value = s->next->value;StackInfo_st *temp = s->next;s->next = s->next->next;/*释放栈顶节点内存*/free(temp);temp = NULL;return SUCCESS;
}
/*访问栈顶元素*/
int stack_top(StackInfo_st *s,ElementType *value)
{/*首先判断栈是否为空*/if(stack_is_empty(s))return FAILURE;*value = s->next->value;return SUCCESS;
}

判断栈是否为空

判断栈空也很简单,只需要判断栈顶指针是否为空即可。

/*判断栈是否为空,空返回1,未空返回0*/
int stack_is_empty(StackInfo_st *s)
{/*栈顶指针为空,则栈为空*/return s->next == NULL;
}

完整可运行代码

代码较长,可点击阅读原文查看或访问:

总结

本文介绍了栈的基本操作以及栈的基本实现。后面将会介绍一些栈的具体应用。


640?wx_fmt=jpeg

扫码或长按关注

回复「 加群 」进入技术群聊

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

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

相关文章

python编写ATM类_Python中编写类的各种技巧和方法

有关 Python 内编写类的各种技巧和方法(构建和初始化、重载操作符、类描述、属性访问控制、自定义序列、反射机制、可调用对象、上下文管理、构建描述符对象、Pickling)。你可以把它当作一个教程,进阶,或者使用参考;我希望它能够成为一份针对…

再说嵌入式入门

我之前写过几篇嵌入式入门的文章 不过我的读者还是觉得不够过瘾,我觉得还是要着重说一下嵌入式软件应该重点学习什么,guoqing收假最后一天写文。精通C语言 精通C语言 精通C语言C语言对于嵌入式软件来说就是他的命脉,不懂C语言的人根本就不能说…

java ios 开发工具_iOS应用开发的五个Java开源工具

随着第三方工具的不断壮大,开发人员逐渐摆脱政策束缚,对于iOS系统的封闭性为其他语言(如Java)开发者诟病得到解脱,开始使用自己熟悉的语言来编写iOS本地应用,或将其他平台上的应用移植到iOS上。本文为你介绍5款开源的开发工具&…

hive 时间转字符串_大数据面试杀招——Hive高频考点,还不会的进来挨打

一、什么是Hive,为什么要用Hive,你是如何理解Hive?面试官往往一上来就一个“灵魂三连问”,很多没有提前准备好的小伙伴基本回答得都磕磕绊绊,效果不是很好。下面贴出菌哥的回答:Hive是基于Hadoop的一个数据仓库工具&a…

java jpa jar_JPA 开发所需的Jar包 (基于Hibernate)

JPA 开发所需的Jar包 (基于Hibernate)(一)下载Sun 的JPA规范(即:Jar包)登陆JavaEE 的 Technologies 页面:http://java.sun.com/javaee/technologies/index.jsp选择 Java Persistence 2.0选择 Final Release 中的 Download Page 后进入下面的界面:下载如下…

C语言入坑指南-数组之谜

前言在C语言中,数组和指针似乎总是“暧昧不清”,有时候很容易把它们混淆。本文就来理一理数组和指针之间到底有哪些异同。数组回顾在分析之前,我们不妨回顾一下数组的知识。数组是可以存储一个固定大小的相同类型元素的顺序集合。为了便于我们…

mysql服务器查绑定的域名查_MySQL使用show status查看MySQL服务器状态信息

MySQL使用show status查看MySQL服务器状态信息这篇文章主要介绍了MySQL使用show status查看MySQL服务器状态信息,需要的朋友可以参考下在LAMP架构的网站开发过程中,有些时候我们需要了解MySQL的服务器状态信息,譬如当前MySQL启动后的运行时间&#xff0c…

Fiddler抓包使用教程-安装配置

转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/72876628 本文出自【赵彦军的博客】 Fiddler是什么? Fiddler是一个http调试代理,它能 够记录所有的你电脑和互联网之间的http通讯,Fiddler 可以也可以让你检查所…

VS2019调试查看变量_你很可能需要知道这个调试小技巧

缘起 最近在调试的时候,需要观察第三方容器中每一个元素的值。默认情况下,vs 并不知道如何显示第三方容器的内容,只能手动观察容器中的每一个值,超级不方便。我找到一个非常给力的好办法,你还知道其它好办法吗&#xf…

Linux i2c子系统驱动probe

I2C 子系统I2C 子系统使用的概率非常大,我之前有做过手机的经验, 手机跑的安卓系统,内核是Linux,手机的很多器件都是用I2C通信的,我经历过从板级设备到dts设备树的阶段,知道I2C在整个系统的举足轻重&#x…

java生成flash_web-flash发布了代码生成插件

web-flash 是一个基于 Spring BootVue.js 的后台管理系统。现在发布了其基于 Intellij IDEA 的代码生成插件!你可以再 idea 插件仓库中搜索 webflash-generator (目前插件在发布审核中,可能会搜索不到),或者直接从本地安装插件:flash-generat…

JAVA多线程程序ProgressBar

JAVA多线程程序ProgressBar 题目简介: 思维导图: 实验代码:建议先看CalThread类,计算线程的实现,再作基本CalFrame类的界面, 然后作ReadThread类,结合CalFrame的组件,最后完善CalFra…

为什么Linux内核里大量使用goto,而很多书籍却不提倡使用?

关于C语言的goto语句存在很多争议,很多书籍都建议“谨慎使用,或者根本不用”。Linux之父Linus在Linux中大量使用goto,也是在启示着我们可以合理使用goto语句。存在即合理,既然是C语言中的一个知识点,我们还是有必要学会…

python特征匹配 查找_特征匹配+单纯形查找对象

我尝试使用opencv获取一个查询图像并在一个基本图像中进行匹配。我看了一下在线教程,你看,他们有示例代码来做这件事。所以我复制并粘贴了代码,并尝试用一些试用图像来运行它。下面是代码和一组图像示例。在import numpy as npimport cv2from…

python数据类型有哪些、分别有什么用途_python中的数据类型有哪些

python中的数据类型有9种,分别是1、字符串2、布尔类型3、整数4、浮点数5、数字6、列表7、元组8、字典9、日期。1、字符串 1.1、如何在Python中使用字符串 a、使用单引号() 用单引号括起来表示字符串,例如:strthis is string; print str; b、使…

java access jdbc_Java连接Access数据库

JDBC(Java DataBase Connectivity)是Java数据库连接API。JDBC能完成与一个数据库建立连接,然后向数据库发送SQL语句,再处理数据库返回的结果。JDBC在设计上和ODBC相似。JDBC和数据库建立连接的一种方式是首先建立起一个JDBC-ODBC桥接器。首先安装office2…

五分钟搞懂什么是红黑树(全程图解)

红黑树,对很多童鞋来说,是既熟悉又陌生。熟悉是因为在校学习期间,准备面试时,这是重点。然后经过多年的荒废,如今已经忘记的差不多了。如果正在看文章的你,马上快要毕业,面临着找工作的压力&…

SequenceFile文件

SequenceFile文件是Hadoop用来存储二进制形式的key-value对而设计的一种平面文件(Flat File)。目前,也有不少人在该文件的基础之上提出了一些HDFS中小文件存储的解决方案,他们的基本思路就是将小文件进行合并成一个大文件,同时对这些小文件的…

win10右键闪退到桌面_WIN10设置闪退,桌面右键个性化显示设置等均无效

开始菜单点击设置,会报错,详细信息记不清了,提示路径C:\Windows\ImmersiveControlPanel\SystemSettings.exe,使用fix it修复工具无效尝试更新系统,更新至最新版本后仍然存在问题事件管理器中找到了这个错误应用程序名称…

Linux 内核红黑树分析

Android binder 内核实现是用红黑树的,理解红黑树我觉得是每一个Linux er的重中之重,感谢格子森同学的投稿,周末愉快。内核版本为 linux4.2.1 本文主要从红黑树的代码实现入手,来讨论linux内核中是如何实现红黑树的(主要是插入和删…