【数据结构】栈(Stack)的实现 -- 详解

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

一、栈的概念及结构

1、概念

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


压栈:栈的插入操作叫做进栈 / 压栈 / 入栈,入数据在栈顶

出栈:栈的删除操作叫做出栈。出数据也在栈顶


2、结构 

【数据结构】栈(Stack)的实现 -- 详解,数据结构,初学者,C语言,c语言,学习,开发语言

 【数据结构】栈(Stack)的实现 -- 详解,数据结构,初学者,C语言,c语言,学习,开发语言


二、栈的实现

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。如果用尾作栈顶(尾插、尾删),那么要用双向链表更好。如果要用单链表实现,那么就用头去作栈顶更好(头插、头删),这样入栈和出栈的效率都是 O(1)。因为栈只会在一端进行插入和删除操作,用数组效率还是比较高,数组在尾上插入数据的代价比较小。当然,也会存在一些问题,就是每次空间不够,要重新开辟空间,可能会造成一些内存浪费。

双向链表虽然不需要考虑内存大小的问题,但实际上价值并不高,在这里使用单向链表好于双向链表,能节省空间。但是,从各个角度而言, 栈的实现还是选择数组的结构来实现更好一些,不需要增容和释放,空间上更加节省,且CPU 高速缓存命中更高一些。


1、栈的顺序存储结构

【数据结构】栈(Stack)的实现 -- 详解,数据结构,初学者,C语言,c语言,学习,开发语言

数组的首元素作为栈底,另外一端作为栈顶,同时定义一个变量 top 来记录栈顶元素在数组中的位置。 


2、栈的链表存储结构 

【数据结构】栈(Stack)的实现 -- 详解,数据结构,初学者,C语言,c语言,学习,开发语言

单链表的尾部作为栈底,头部作为栈顶,方便插入和删除(进栈头插,出栈头删),头指针和栈顶指针 top 合二为一。


三、栈的实现

1、创建文件

  • test.c(主函数、测试栈各个接口功能)
  • Stack.c(栈接口函数的实现)
  • Stack.h(栈的类型定义、接口函数声明、引用的头文件)

2、Stack.h 头文件代码

下面是动态增长的栈的结构,在实际中更常用。

#pragma once
#include <stdio.h>
#include <assert.h> // assert
#include <stdlib.h> // realloc
#include <stdbool.h> // bool

// 支持动态增长的栈
typedef int STDataType; // 类型重命名 栈中元素类型先假设为int

typedef struct Stack
{
    STDataType* a; // 指向动态开辟的数组
    int top; // 记录栈顶位置
    int capacity; // 栈的容量大小
}Stack;

// 初始化栈
void StackInit(Stack* ps); 
// 销毁栈
void StackDestroy(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); 

四、Stack.c 中各个接口函数的实现

1、栈的初始化

// 初始化栈
void StackInit(Stack* ps)
{
	assert(ps);
	ps->a = NULL;
    
    //思路一:
	ps->top = 0; // 意味着top指向栈顶数据的下一个

    //思路二:
    //ps->top = -1; // 意味着top指向栈顶数据
    
	ps->capacity = 0;
}

思路二: 

【数据结构】栈(Stack)的实现 -- 详解,数据结构,初学者,C语言,c语言,学习,开发语言


2、栈的销毁

// 销毁栈
void StackDestroy(Stack* ps)
{
	assert(ps);
	if (ps->a)
	{
		free(ps->a);
	}
    ps->a = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

3、入栈

// 入栈
void StackPush(Stack* ps, STDataType x)
{
	assert(ps);

	if (ps->top == ps->capacity) // 检查栈空间是否满了
	{
		int newCapacity = (ps->capacity == 0) ? 4 : (ps->capacity) * 2;
		STDataType* tmp = realloc(ps->a, sizeof(STDataType) * newCapacity); // 扩容至新容量
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newCapacity; // 更新容量
	}
	ps->a[ps->top] = x; // 将新增元素放入栈顶空间
	ps->top++; // 栈顶指针加一
}

4、出栈

// 出栈
void StackPop(Stack* ps)
{
	assert(ps);
	assert(!StackEmpty(ps)); // 栈不能为空
	ps->top--; // 栈顶指针减一
}

5、获取栈顶元素

// 获取栈顶元素
STDataType StackTop(Stack* ps)
{
	assert(ps);
    assert(!StackEmpty(ps)); // 栈不能为空
	return ps->a[ps->top-1];
}

6、获取栈中有效元素个数

// 获取栈中有效元素个数
int StackSize(Stack* ps)
{
	assert(ps);
	return ps->top;
}

7、检测栈是否为空

// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
bool StackEmpty(Stack* ps)
{
	assert(ps);

    //写法一:
    /*if (ps->top == 0)
	{
		return true;
	}
	else
	{
		return false;
	}*/

    //写法二:
	return ps->top == 0;
}

五、代码整合

// Stack.c
#include "Stack.h"

// 初始化栈
void StackInit(Stack* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->top = 0; // 意味着top指向栈顶数据的下一个
	ps->capacity = 0;
}

// 销毁栈
void StackDestroy(Stack* ps)
{
	assert(ps);
	if (ps->a)
	{
		free(ps->a);
	}
    ps->a = NULL;
	ps->top = 0;
	ps->capacity = 0;
}

// 入栈
void StackPush(Stack* ps, STDataType x)
{
	assert(ps);

	if (ps->top == ps->capacity) // 检查栈空间是否满了
	{
		int newCapacity = (ps->capacity == 0) ? 4 : (ps->capacity) * 2;
		STDataType* tmp = realloc(ps->a, sizeof(STDataType) * newCapacity); //扩容至新容量
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newCapacity; // 更新容量
	}
	ps->a[ps->top] = x; // 将新增元素放入栈顶空间
	ps->top++; // 栈顶指针加一
}

// 出栈
void StackPop(Stack* ps)
{
	assert(ps);
	assert(!StackEmpty(ps)); // 栈不能为空
	ps->top--; // 栈顶指针减一
}

// 获取栈顶元素
STDataType StackTop(Stack* ps)
{
	assert(ps);
    assert(!StackEmpty(ps)); // 栈不能为空
	return ps->a[ps->top-1];
}

// 获取栈中有效元素个数
int StackSize(Stack* ps)
{
	assert(ps);
	return ps->top;
}

// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
bool StackEmpty(Stack* ps)
{
	assert(ps);
	return ps->top == 0;
}

六、测试栈的功能

栈的实现不能像顺序表一样,去实现一个打印函数来遍历栈并输出,这样做就不符合栈的特点了(只能在栈顶插入删除,后进先出),所以我们这样来实现出栈:获取并打印栈顶元素,再删除栈顶元素,继续获取新的栈顶元素。

【数据结构】栈(Stack)的实现 -- 详解,数据结构,初学者,C语言,c语言,学习,开发语言文章来源地址https://www.toymoban.com/news/detail-619619.html

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

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

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

相关文章

  • 【C语言】代码实现 扫雷 游戏及进阶功能(初学者详解)

    扫雷游戏的起源可以追溯到20世纪60年代,当时这款游戏是由IBM开发出来的。在80年代初,微软公司将其收归旗下,并将其作为Windows操作系统自带的一款游戏。自此以后,扫雷成为了Windows用户最喜欢的休闲游戏之一,也受到了全球范围内的玩家喜爱。 现在,我们使用C语言,来

    2024年01月20日
    浏览(45)
  • 【数据结构与算法】6、栈(Stack)的实现、LeetCode:有效的括号

    🌱 栈 是一种特殊的线性表, 只能在一端进行操作 🌱 往栈中 添加 元素的操作,一般叫做 push ( 入栈 ) 🌱 从栈中 移除 元素的操作,一般叫做 pop ,出栈(只能移除栈顶元素),也叫做: 弹出栈顶元素 🌱 后进先出 的原则, L ast I n F irst O ut, LIFO 注意:这里的 栈 与内

    2024年02月13日
    浏览(38)
  • 自定义类型:结构体----初学者笔记

    目录 1. 结构体类型的声明 1.1 结构体类型的简单介绍和声明 1.1.1 结构的声明 1.1.2 特殊的声明 1.1.3 结构的自引用 2. 结构体变量的创建和初始化 3. 结构成员访问操作符 4. 结构体内存对⻬ 4.1 对齐规则 4.2 练习 4.2.1 练习1 4.2.2 练习2 4.3 为什么存在内存对⻬? 4.4 修改默认对齐数

    2024年02月07日
    浏览(56)
  • 数据结构---栈(Stack)

    栈是一种 线性 数据结构 栈是\\\" 后进先出 (LIFO---Last In First Out)\\\"的数据结构(盘子的叠放:当服务员将新的盘子放在餐桌上时,他们通常会将盘子放在已有的盘子堆的顶部。当顾客用完盘子后,服务员会从堆顶取走盘子。这个过程就类似于栈的入栈和出栈操作。) 规定只能从 栈顶

    2024年01月21日
    浏览(39)
  • 数据结构——栈(Stack)

    目录 1.栈的介绍 2.栈工程 2.1 栈的定义 2.1.1 单链表实现栈 2.1.2 数组实现栈 2.1.2.1 静态数组栈 2.1.2.2 动态数组栈 2.2 栈的函数接口 2.2.1 栈的初始化 2.2.2 栈的数据插入(入栈) 2.2.3 栈的数据删除(出栈) 2.2.4 判断栈是否为空 2.2.5 取栈顶数据 2.2.6 栈数据统计 2.2.7 栈销毁 3. 栈总

    2024年01月21日
    浏览(41)
  • [数据结构 -- C语言] 栈(Stack)

    目录 1、栈 1.1 栈的概念及结构 2、栈的实现 2.1 接口 3、接口的实现 3.1 初始化 3.2 入栈/压栈 3.3 出栈 3.4 获取栈顶元素 3.5 获取栈中有效元素个数 3.6.1 bool 类型接口 3.6.2 int 类型接口 3.7 销毁栈 4、完整代码 5、功能测试 栈:一种特殊的线性表,其只允许在固定的一端进行插入和

    2024年02月05日
    浏览(31)
  • 【数据结构】 栈(Stack)的应用场景

    栈(Stack)又名堆栈,作为一个== 先进后出== 的数据结构。 它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使

    2024年02月11日
    浏览(39)
  • 在JavaScript中的栈数据结构(Stack )

    JavaScript 中可以通过数组实现栈数据结构。栈是一种遵循后进先出(LIFO)原则的数据结构,它只允许在栈顶进行插入和删除操作。 栈是一种遵从后进先出(LIFO)原则的有序集合。新添加的或待删除的元素都保存在栈的 同一端,称作栈顶,另一端就叫栈底。在栈里,新元素都

    2024年02月10日
    浏览(37)
  • Python初学者友好丨详解参数传递类型

    摘要:  本文清晰地解释了Python中的不同参数传递类型,并提供了示例代码来说明每种类型的用法。对于初学者或不清楚Python传参的读者们来说是非常有益的,文中提供了足够的信息来理解和使用Python中的函数参数传递。 本文分享自华为云社区《提升Python函数调用灵活性:参

    2024年02月09日
    浏览(43)
  • 【STM32】初学者必读STM32时钟系统详解

    目录 1 前言 2 时钟系统介绍 3 时钟源 3.1 系统时钟源 3.2 次级时钟源 3.3 时钟源特点 4 时钟 4.1 AHB总线时钟 4.2 APB1总线时钟 4.3 APB2总线时钟 5 时钟控制器 6 CubeMx配置时钟系统 6.1 选择单片机型号 6.2 选择时钟源 6.3 配置系统时钟 6.4 时钟系统初始化代码 7 结论         STM32的时

    2024年02月08日
    浏览(50)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包