【数据结构】栈及其实现

这篇具有很好参考价值的文章主要介绍了【数据结构】栈及其实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

🤠前言

什么是栈?

栈的定义及初始化

栈的定义

栈的初始化

栈的判空

栈顶压栈

栈顶出栈

栈的数据个数

栈的销毁

完整代码

总结


🤠前言

  • 学了相当长一段时间的链表,总算是跨过了一个阶段。从今天开始我们将进入栈和队列的学习,相比于链表可以说是有手就行的难度,所以各位老铁可以轻松一波啦,不必太担心。
  • 栈和队列我们分开来讲,本篇主要详解栈及其实现
  • 栈的特点是先进后出,后进先出(LIFO),这一特点以及进一步运用(单调栈)是一些算法题的突破口,后续我也会分享LeetCode的一些题,希望大家关注点点,以免错过哦!

什么是栈?

我们前面学习的顺序表(数组)以及链表可以说是数据结构的物理结构,而栈和队列则是数据结构的逻辑结构。

这是什么意思呢?

如果把数据结构比作活生生的人,那么物理结构就是人的血肉和骨骼,看得见摸得着,在内存中也实际存储这;逻辑结构则是思想灵魂,看不见摸不着,它依赖于物理结构而存在。

简而言之,栈和队列其实都是由数组或者链表实现的,不过在此基础上加了一些限制条件以适用于不同场景,将其抽化成了一个数据结构

栈的定义及初始化

栈的定义

  • 我们采用数组的方式实现栈,因为数组比链表的缓存命中率更高(粗暴点来说cpu访问的速度会更快,访问没用的信息的数量会减少,这里就不具体展开了)。
  • 还是定义一个结构体来实现栈,分别为数组(此处应该用malloc,这样不够的时候可以扩容)
  • top用来表示栈顶,因为栈只在栈顶一段进行操作
  • capacity用来记录栈的容量。
typedef int STDataType;
typedef struct Stack
{
	int top;
	int capacity;
	STDataType* a;
}ST;

栈的初始化

  • 在进行插入的时候再开辟空间,为了防止野指针问题,将a置为NULL,capacity显而易见应该也为0
  • 关于top就有一点讲究,如果top置为0则指向最后一个数据的下一个,如果置为-1指向最后一个有效数据。因为每次插入数据后top才++,不是很理解的小伙伴们可以画一个数组模拟一下。
  • 我们这里就将top初始化为0,其也间接体现了存储数据的个数
  • 当然传进来的栈不能为空指针啦,不然相当于栈都还没创建,老生常谈的问题了,每个函数接口前都要assert暴力断言一下,下文就不赘述了

以下为函数接口实现:
 

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

	ps->capacity = ps->top = 0;//指向最后一个数据的下一个
	ps->a = NULL;
}

栈的判空

上文提到top间接表示了存储数据的个数,所以我们直接判断top是否为0即可。

以下为函数接口实现:

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

	return ps->top == 0;
}

栈顶压栈

  • 在数据结构中的学习当中,插入数据往往需要考虑扩容的问题,此处也是。当top==capacityd的时候我们就扩容
  • 插入后top需要++一下,而扩容后capacity则需要更新(易忘)
  • 这里应该包括了当top==0的情况,因为初始化的时候没有开辟空间

【数据结构】栈及其实现

以下为函数接口实现:

void StackPush(ST* ps, STDataType x)
{
	assert(ps);
	
	//当内存满了则需要扩容
	if (ps->top== ps->capacity)
	{
		int newcapacity = (ps->capacity == 0) ? 4 : ps->capacity * 2;
		STDataType *tmp=(STDataType*)realloc(ps->a, newcapacity);
		if (tmp == NULL)
		{
			perror("malloc fail\n");
			return;
		}
		else
		{
			ps->capacity = newcapacity;
			ps->a = tmp;
		}
	}
	//没满就直接压栈即可
	ps->a[ps->top] = x;
	ps->top++;
}

栈顶出栈

  • 删除数据,往往需要考虑数据结构是否为空的情况,这里就可以用到上文的StackEmpty函数接口了,增加了代码的可读性
  • 和顺序表删除数据一样,只需要top--即可,并不需要真的抹除其数据,下次入栈的时候新的数据就会覆盖原来的数据。
  • capacity不需要变化,因为其表示栈的容量

以下为函数接口实现:

void StackPop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));

	ps->top--;
}

栈的数据个数

  • 上文说了top初始化为0的时候代表数据个数,所以这里直接返回top即可
  • 数据个数一定为整数,所以用int即可,unsigned int也行

以下为函数接口实现:

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

	return ps->top;
}

获取栈顶元素

  • 函数返回类型应该为数组存储的数据类型,而不要思维固化的写为int
  • 因为top初始化为0,指向最后一个数据的下一个位置,所以我们要返回top-1位置的数据
  • 当栈为空的时候肯定获取不了啦,所以这里还是assert断言爆打

以下为函数接口实现:

STDataType StackTop(ST* ps)//获得栈顶元素
{
	assert(ps);
	assert(!StackEmpty(ps));

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

栈的销毁

切记不可直接free掉代表栈的结构体就以为把栈销毁了,要先free掉结构体里的数组,然后再free掉代表栈的结构体,不然会内存泄漏!!!

以下为函数接口实现:

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

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

完整代码

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

	ps->capacity = ps->top = 0;//指向最后一个数据的下一个
	ps->a = NULL;
}

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

	return ps->top == 0;
}
void StackPush(ST* ps, STDataType x)
{
	assert(ps);
	
	//当内存满了则需要扩容
	if (ps->top== ps->capacity)
	{
		int newcapacity = (ps->capacity == 0) ? 4 : ps->capacity * 2;
		STDataType *tmp=(STDataType*)realloc(ps->a, newcapacity);
		if (tmp == NULL)
		{
			perror("malloc fail\n");
			return;
		}
		else
		{
			ps->capacity = newcapacity;
			ps->a = tmp;
		}
	}
	//没满就直接压栈即可
	ps->a[ps->top] = x;
	ps->top++;
}
void StackPop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));

	ps->top--;
}
STDataType StackTop(ST* ps)//获得栈顶元素
{
	assert(ps);
	assert(!StackEmpty(ps));

	return ps->a[ps->top-1];
}
int StackSize(ST* ps)
{
	assert(ps);

	return ps->top;
}

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

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

总结

😊相比于链表,栈实现起来简直不要简单太多,但是大家别懈怠,后面还有二叉树在等着我们呢,现在只是过渡期,继续努力哦!

❤️我也会继续输出数据结构相关的博客的,希望大家多多支持!!!

感谢阅读本小白的博客,如果错误请指出,一定虚心采纳!文章来源地址https://www.toymoban.com/news/detail-459705.html

到了这里,关于【数据结构】栈及其实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【数据结构】二叉树链式结构的实现及其常见操作

    目录 1.手搓二叉树 2.二叉树的遍历 2.1前序、中序以及后序遍历 2.2二叉树的层序遍历 3.二叉树的常见操作 3.1求二叉树节点数量 3.2求二叉树叶子节点数量 3.3求二叉树第k层节点个数 3.3求二叉树的深度 3.4二叉树查找值为x的节点 4.二叉树的销毁 在学习二叉树的基本操作前,需先要

    2024年02月12日
    浏览(45)
  • 【数据结构】| 并查集及其优化实现

    以一个直观的问题来引入并查集的概念。 亲戚问题:有一群人,他们属于不同家族,同一个家族里的人互为亲戚,不同家族的人不是亲戚。随机指定两个人,问他们是否有亲戚关系。 以下图3个不相交的集合表示 3 个家族,当询问两个人是否有亲戚关系时,也就是问两个元素

    2024年02月09日
    浏览(37)
  • 数据结构笔记1线性表及其实现

    终于开始学习数据结构了 c语言结束之后 我们通过题目来巩固了 接下来我们来学习数据结构 这里我们将去认识到数据结构的一些基础知识,我在第一次学习的时候会很迷糊现在重新学习发现之前的时候还是因为c语言学的不牢固导致学习数据结构困难 这里 我会尽量的多写代

    2024年02月22日
    浏览(40)
  • 【数据结构与算法】之顺序表及其实现!

    目录 ​编辑 1. 顺序表的概念及结构 2. 接口的实现 2.1 顺序表的初始化 2.2 检查顺序表容量是否已满 2.3 顺序表的尾插 ​编辑 2.4 顺序表的尾删 2.5 顺序表的头插 2.6  顺序表的头删 2.7 顺序表在pos位置插入 2.8  顺序表在pos位置删除 2.9 顺序表的查找 2.10 顺序表的销毁 2.1

    2024年04月28日
    浏览(33)
  • 【数据结构】带头双向循环链表及其实现

    目录 1.带头双向循环链表 2.带头双向循环链表实现 2.1初始化 2.2销毁 2.3头插 2.4链表打印 2.5头删数据 2.6尾插数据 2.7尾删数据 2.8链表判空  2.9查找一个数据 2.10在pos位置前插入数据 2.11删除pos位置 2.12求链表的长度 2.顺序表和链表的比较 我们已经实现了无头单向循环链表 带头双

    2024年02月10日
    浏览(45)
  • 【数据结构之树】初阶数据结构之树的实现及其各种方式(上)

    👻作者简介:M malloc,致力于成为嵌入式大牛的男人 👻专栏简介:本文收录于 初阶数据结构 ,本专栏主要内容讲述了初阶的数据结构,如顺序表,链表,栈,队列等等,专为小白打造的文章专栏。 👻相关专栏推荐:LeetCode刷题集,C语言每日一题。 本篇文章我将详细的讲解

    2024年02月17日
    浏览(46)
  • 深入理解数据结构:队列的实现及其应用场景

    队列(Queue)是一种具有先进先出(FIFO)特性的数据结构。在队列中,数据的插入和删除操作分别在队列的两端进行。插入操作在队列的尾部进行,而删除操作则在队列的头部进行。这种特性使得队列在很多实际应用中非常有用,比如任务调度、缓冲区管理等。 线性表是一种

    2024年04月28日
    浏览(51)
  • 【数据结构与算法】之双向链表及其实现!

    ​                                                                                 个人主页:秋风起,再归来~                                                                                             数据结构与

    2024年04月23日
    浏览(42)
  • c语言数据结构——链表的实现及其基本操作

    顺序表的问题及思考 问题: 中间/头部的插入删除,时间复杂度为O(N) 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到 200,我们再继续插入了5个数据,后面没有数据插

    2023年04月09日
    浏览(82)
  • 【redis】redis的5种数据结构及其底层实现原理

    Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(无序集合)及zset(有序集合)。 在秒杀项目里,我用过redis的Set和Hash结构: String:一个 key 对应一个字符串,string是Redis 最基本的数据类型。(字节的abase框架只实现了redis的string数据结构,导致我们如

    2024年02月09日
    浏览(72)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包