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

一、栈的概念及结构

1、概念

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


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

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


2、结构 

 


二、栈的实现

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为栈只会在一端进行插入和删除操作,用数组效率还是比较高,数组在尾上插入数据的代价比较小。当然,也会存在一些问题,就是每次空间不够,要重新开辟空间,可能会造成一些内存浪费。

1、栈的顺序存储结构

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


2、栈的链表存储结构 

单链表的尾部作为栈底,头部作为栈顶,方便插入和删除(进栈头插,出栈头删),头指针和栈顶指针 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; // 类型重命名 栈中元素类型先假设为inttypedef 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;
}

思路二: 

 


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;
}

六、测试栈的功能

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

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

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

相关文章

SpringBoot的pom文件、容器、组件

一、pom文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4…

求分享如何批量压缩视频的容量的方法

视频内存过大&#xff0c;不但特别占内存&#xff0c;而且还会使手机电脑出现卡顿的现象&#xff0c;除此之外&#xff0c;如果我们想发送这些视频文件可能还会因为内存太大无法发送。因此&#xff0c;我们可以批量地压缩视频文件的内存大小&#xff0c;今天小编要来分享一招&a…

聊聊原子弹之父:奥本海默

最近诺兰的电影奥本海默即将热映,其改编自Kai Bird和 Martin J. Sherwin的 2005 年Pulitzer Prize 获奖小说:“American Prometheus: The Triumph and Tragedy of J. Robert Oppenheimer”。这本小说作者研究奥本海默25年,才得以成形,可见奥神本人身上的故事曲折和传奇。 …

Arrays(数组)工具类

java.util.Arrays 是一个与数组相关的工具类&#xff0c;里面提供了大量静态方法&#xff0c;用来实现数组常见的操作。 Arrays.toString ( 数组名 )将参数数组变成字符串&#xff08;按照默认格式&#xff1a;[10, 20, 30]&#xff09;Array.sort ( 数组名 ) 按照默认升序&…

数据库索引优化与查询优化——醍醐灌顶

索引优化与查询优化 哪些维度可以进行数据库调优 索引失效、没有充分利用到索引-一索引建立关联查询太多JOIN (设计缺陷或不得已的需求) --SQL优化服务器调优及各个参数设置 (缓冲、线程数等)–调整my.cnf数据过多–分库分表 关于数据库调优的知识点非常分散。不同的 DBMS&a…

Pycharm工具Python开发自动添加注释(详细)

方法自动添加参数注释 定义了一个函数&#xff0c;在函数下面敲入了三个双引号后&#xff0c;enter回车并没有自动出现注释&#xff0c;如图&#xff1a; 解决办法 Pycharm中依次打开File —> Settings —> Tools —> Python Integrated Tools&#xff0c;如图&…

isp调试工具环境搭建及其介绍!

一、isp调试环境搭建&#xff1a; 后期调试isp&#xff0c;是在rv1126提供的RKISP2.x Tuner工具上进行调试&#xff0c;所以我们大前提必须要把这个环境和一些操作先搞熟悉来&#xff0c;后面有一些专用术语&#xff0c;我们遇到了再去看&#xff0c;现在专门看一些专用术语&am…

【TypeScript】类型声明及应用(二)

【TypeScript】类型声明及应用&#xff08;二&#xff09; 一、前言 TypeScript开发中需要对定义的变量指定类型&#xff0c;目前版本都支持哪些类型&#xff0c;每一个类型都有哪些含义&#xff0c;在这篇文章中&#xff0c;我们将会对其进行总结说明 二、JavaScript基本数据…

Scrapy和Selenium整合(一文搞定)

文章目录 前言一、开始准备1. 包管理和安装chrome驱动2. 爬虫项目的创建&#xff08;举个栗子&#xff09;3. setting.py的配置 二、代码演示1. 主爬虫程序2. 中间件的配置3. 定义item对象4. 定义管道 总结 前言 scrapy和selenium的整合使用 先定个小目标实现万物皆可爬&#…

Pycharm debug程序,跳转至指定循环条件/循环次数

在断点出右键&#xff0c;然后设置条件 示例 for i in range(1,100):a i 1b i 2print(a, b, i) 注意&#xff1a; 1、你应该debug断点在循环后的位置而不是循环上的位置&#xff0c;然后你就可以设置你的条件进入到指定的循环上了 2、设置条件&#xff0c;要使用等于符号…

C# Assembly 反射动态加载程序集(动态加载Dll)Demo

No1、本Demo 定义了一个接口IserviceToolFrame&#xff0c;接口中有一个方法Run。 No2、在另外两个工程中&#xff0c;分别定义两个类serviceToolCatComplete、serviceToolDogComplete实现接口IserviceToolFrame。 No3、控制台程序通过动态加载Dll的方式去调用IserviceToolFram…

Flutter 使用texture_rgba_renderer实现桌面端渲染视频

Flutter视频渲染系列 第一章 Android使用Texture渲染视频 第二章 Windows使用Texture渲染视频 第三章 Linux使用Texture渲染视频 第四章 全平台FFICustomPainter渲染视频 第五章 Windows使用Native窗口渲染视频 第六章 桌面端使用texture_rgba_renderer渲染视频&#xff08;本…

#P0999. [NOIP2008普及组] 排座椅

题目描述 上课的时候总会有一些同学和前后左右的人交头接耳&#xff0c;这是令小学班主任十分头疼的一件事情。不过&#xff0c;班主任小雪发现了一些有趣的现象&#xff0c;当同学们的座次确定下来之后&#xff0c;只有有限的 DD 对同学上课时会交头接耳。 同学们在教室中坐…

《GreenPlum系列-部署维护》GreenPlum数据库Standby故障处理

一、Standby故障 1.检查监控中心数据库状态 2.查看master节点数据库状态 su - gpadmin gpstate -f二、重启数据库 1.快速关闭数据库 [gpadminmdw pg_log]$ gpstop -M fast ... Continue with Greenplum instance shutdown Yy|Nn (defaultN): > y ...2.开启数据库 [gpad…

Redis以及Java使用Redis

一、Redis的安装 Redis是一个基于内存的 key-value 结构数据库。 基于内存存储&#xff0c;读写性能高 适合存储热点数据&#xff08;热点商品、资讯、新闻&#xff09; 企业应用广泛 官网&#xff1a;https://redis.io 中文网&#xff1a;https://www.redis.net.cn/ Redis…

【LeetCode】单链表——刷题

你曾经灼热的眼眶&#xff0c;是人生中少数的笨拙又可贵的时刻。 文章目录 1.反转单链表 题目思路及图解 代码中需要注意的问题 2.移除链表元素 题目思路及图解 代码中需要注意的问题 大家好&#xff0c;我是纪宁。 这篇文章分享给大家一些经典的单链表leetcode笔试题的…

类变量和类方法

类变量和类方法 引入 思考&#xff1a;有一群小孩在玩堆雪人&#xff0c;不时有新的小孩加入&#xff0c;请问如何知道现在有多少小孩在玩&#xff1f; 静态变量内存分析 1、静态变量被对象共享 2、静态变量可能在堆中&#xff0c;也可能在方法区的静态域中&#xff0c;这…

Flutter 的线程模型和异步原理

本文字数&#xff1a;&#xff1a;36130字 预计阅读时间&#xff1a;91分钟 在Android应用中&#xff0c; 用户时常会遇到界面卡顿的情况&#xff0c;非常影响用户的体验。作为Android开发肯定都知道&#xff1a;应用在主线程里做了大量的耗时操作(例如文件读写&#xff0c; 数…

stable diffusion打造自己专属的LORA模型

通过Lora小模型可以控制很多特定场景的内容生成。 但是那些模型是别人训练好的&#xff0c;你肯定很好奇&#xff0c;我也想训练一个自己的专属模型&#xff08;也叫炼丹&#xff5e;_&#xff5e;&#xff09;。 甚至可以训练一个专属家庭版的模型&#xff08;family model&…

RT1052 的周期定时器

文章目录 1 PIT 周期中断定时器2 PIT定时器的使用3 PIT定时器配置3.1 PIT 时钟使能。3.1.1 CLOCK_EnableClock 3.2 初始化 PIT 定时器3.2.1 PIT_Init 3.3 设置 通道 0 的 加载值3.3.1 PIT_SetTimerPeriod 3.4 使能 通道 0 的中断3.4.1 PIT_EnableInterrupts 3.5 开启 PIT 定时器…