#数据结构 链式栈

1. 概念

链式栈LinkStack

  1. 逻辑结构:线性结构
  2. 物理结构:链式存储
  3. 栈的特点:后进先出

栈具有后进先出的特点,我们使用链表来实现栈,即链式栈。那么栈顶是入栈和出栈的地方,单向链表有头有尾,那我们将链表的头作为栈顶还是链表的尾作为栈顶呢?如果每次在链表的尾部进行插入或删除,就需要遍历整个链表来找到尾结点即终端结点。而在头部即起始结点进行插入或删除时,仅需头指针找到链表的起始结点,而无需遍历整个链表。

所以链式栈的入栈、出栈都是通过对链表进行头插、头删来实现。

既然要对单向链表进行头插、头删,那么头结点的存在会让操作变得复杂,故我们使用无头单向链表。

无头单向链表的头就是栈顶,故栈针是指向无头单向链表的起始结点的,所以我们在链式栈中将头指针H称做栈针top。top栈针永远指向无头单向链表的第一个节点,栈空的时候除外。

对于链栈来说,基本不存在栈满的情况,除非内存已经没有可以使用的空间。

对于空栈来说,链表即H == NULL,链式栈即top == NULL

2. 接口实现

#ifndef _LINKSTACK_H_
#define _LINKSTACK_H_
#include <stdio.h>
#include <stdlib.h>
//入栈和出栈只在第一个节点位置操作
typedef int datatype;
typedef struct linkstack
{datatype data;//数据域struct linkstack *next;//指针域
}linkstack_t;
//1.创建一个空的栈
void CreateEpLinkStack(linkstack_t **ptop);
//2.入栈   data是入栈的数据
//参数上之所以采用二级指针,因为我们要随着入栈添加新的节点作为头,top需要永远指向当前链表的头,那么修改main函数中的top,我们采用地址传递
int PushLinkStack(linkstack_t **ptop, datatype data);
//3.判断栈是否为空
int IsEpLinkStack(linkstack_t *top);
//4.出栈
datatype PopLinkStack(linkstack_t **ptop);
//5.清空栈
void ClearLinkStack(linkstack_t **ptop);//用二级指针,是因为清空后需要将main函数中的top变为NULL
//6.求栈的长度
int LengthLinkStack(linkstack_t *top);//用一级指针,是因为我只是求长度,不需要修改main函数中top指针的指向
//7.获取栈顶数据,不是出栈,不需要移动main函数中的top,所以用一级指针
datatype GetTopLinkStack(linkstack_t *top);
#endif

2.1. 定义操作链式栈的结构体

//入栈和出栈只在第一个节点位置操作
typedef int datatype;
typedef struct linkstack
{datatype data;//数据域struct linkstack *next;//指针域
}linkstack_t;

2.2. 创建空的链式栈

#include "linkstack.h"
void CreateEpLinkStack(linkstack_t **ptop)
{	//top = NULL;*ptop = NULL;
}
#include "linkstack.h"
int main(int argc, const char *argv[])
{linkstack_t *top;CreateEpLinkStack(&top);return 0;
}

2.3. 入栈

思想:

开辟新结点存放入栈数据

每次都将新结点链接到无头单向链表的头

栈针top永远指向无头单向链表的头,栈空时除外

顺序栈需要判满,但链式栈无需判满

/*2.入栈   data是入栈的数据
//参数上之所以采用二级指针,因为我们要随着入栈添加新的节点作为头,top需要永远指向当前链表的头,
//那么修改main函数中的top,我们采用地址传递*/
int PushLinkStack(linkstack_t **ptop, datatype data)
{	linkstack_t *pnew = (linkstack_t *)malloc(sizeof(linkstack_t));if(NULL == pnew){printf("PushLinkStack pnew malloc failed\n");return -1;}//给新节点初始化pnew->data = data;pnew->next = *ptop;      *ptop = pnew;return 0;
}
#include "linkstack.h"
int main(int argc, const char *argv[])
{linkstack_t *top;CreateEpLinkStack(&top);int i;for(i = 0; i < 5; i++){PushLinkStack(&top,i);}return 0;
}

2.4. 出栈

顺序栈需要判空即PS->top==-1

链式栈也需要判空即top == NULL

判空无需改变主函数栈针top的指向,故无需传递top的地址。

但出栈后需要移动栈针,改变top的指向,故需要传递栈针top的地址&top

综上,出栈函数需要传递栈针top的地址&top

//3.判断栈是否为空
int IsEpLinkStack(linkstack_t *top)
{return top == NULL;
}
//4.出栈
datatype PopLinkStack(linkstack_t **ptop)
{if(IsEpLinkStack(*ptop)){printf("PopLinkStack failed\n");return -1;}datatype temp;linkstack_t *pdel = NULL;
#if 0pdel = *ptop;temp = pdel->data;*ptop = pdel->next;free(pdel);pdel = NULL;return temp;
#endif
#if 1temp = (*ptop)->data;pdel = *ptop;*ptop = (*ptop)->next;free(pdel);pdel = NULL;return temp;
}
#include "linkstack.h"
int main(int argc, const char *argv[])
{linkstack_t *top;CreateEpLinkStack(&top);int i;for(i = 0; i < 5; i++){PushLinkStack(&top,i);}
#if 0for(i = 0; i < 5; i++)	printf("%d ",PopLinkStack(&top));}printf("\n");		
#endifreturn 0;
}
4 3 2 1 0 

2.5. 栈长

问:求栈长是否需要传递栈针的地址? 无需

问:求栈长能否传递栈针的地址? 可以

//6.求栈的有效长度
int LengthLinkStack(linkstack_t *top)//用一级指针,是因为我只是求长度,不需要修改main函数中top指针的指向
{int len = 0;while(top != NULL){len++;top = top->next;}return len;
}
#include "linkstack.h"
int main(int argc, const char *argv[])
{linkstack_t *top;CreateEpLinkStack(&top);int i;for(i = 0; i < 5; i++){PushLinkStack(&top,i);}
#if 0for(i = 0; i < 5; i++){printf("%d ",PopLinkStack(&top));}printf("\n");		
#endifprintf("len:%d\n",LengthLinkStack(top));
return 0;
}

2.6. 获取栈顶数据

问:获取栈顶数据是否需要移动栈针?

问:获取栈顶数据是否需要传递栈针地址?

获取栈顶数据,部署出栈,无需移动栈针,故无需传递栈针top的地址&top

//7.获取栈顶数据,不是出栈,不需要移动main函数中的top,所以用一级指针
datatype GetTopLinkStack(linkstack_t *top)
{if(!IsEpLinkStack(top)){return top->data;}return -1;
}
#include "linkstack.h"
int main(int argc, const char *argv[])
{linkstack_t *top;CreateEpLinkStack(&top);int i;for(i = 0; i < 5; i++){PushLinkStack(&top,i);}
#if 0for(i = 0; i < 5; i++){printf("%d ",PopLinkStack(&top));}printf("\n");		
#endifprintf("len:%d\n",LengthLinkStack(top));printf("top_data%d\n",GetTopLinkStack(top));return 0;
}

2.7. 清空

只要不空一直出栈

//5.清空栈
void ClearLinkStack(linkstack_t **ptop)//用二级指针,是因为清空后需要将main函数中的top变为NULL
{	while(!IsEpLinkStack(*ptop)){PopLinkStack(ptop);}
}
#include "linkstack.h"
int main(int argc, const char *argv[])
{linkstack_t *top;CreateEpLinkStack(&top);int i;for(i = 0; i < 5; i++){PushLinkStack(&top,i);#if 0for(i = 0; i < 5; i++){printf("%d ",PopLinkStack(&top));}printf("\n");		
#endifprintf("len:%d\n",LengthLinkStack(top));printf("top_data%d\n",GetTopLinkStack(top));ClearLinkStack(&top);return 0;
}

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

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

相关文章

Http中get与post的区别,99%的人都理解错了吧

Get和Post是HTTP请求的两种基本方法&#xff0c;要说它们的区别&#xff0c;接触过WEB开发的人都能说出一二。 最直观的区别 就是Get把参数包含在URL中&#xff0c;Post通过request body传递参数。 你可能自己写过无数个Get和Post请求&#xff0c;或者已经看过很多权威网站总…

【ARMv8/v9 GIC 系列 5.7 -- 中断路由与系统寄存器】

请阅读【ARM GICv3/v4 实战学习 】 文章目录 Interrupt routing and System register access与Group 0中断相关的寄存器与Group 1中断相关的寄存器公共寄存器Interrupt routing and System register access 在执行AArch64状态时,中断路由到异常级别(Exception Level)是由以…

容器:stack

以下是关于stack容器的一些总结&#xff1a; stack容器比较简单&#xff0c;主要包括&#xff1a; 1、构造函数&#xff1a;stack [staName] 2、添加、删除元素: push() 、pop() 3、获取栈顶元素&#xff1a;top() 4、获取栈的大小&#xff1a;size() 5、判断栈是否为空&#x…

Linux运维之管道符、重定向与环境变量

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 目录 一、输入输出重定向 二、管道命令符 三、命令行的通配符 四、常用的转义字符 五、重要的环境变量 致谢 一、输入输出重定向 输入重定向是…

javascripr如何设计弹出输入框并在网页内输出输入内容

javascript如何设计弹出输入对话框 这里就需要用到prompt语言 它的语法格式是 prompt(对话框内容&#xff09; 如何把在对话框里输入内容输出到网页里&#xff0c;需要先定义一个变量&#xff0c;用var或let都可以。 假定变量名为a&#xff0c;代码是 let aprompt(请输入…

Python统计实战:时间序列分析之一元线性回归预测和指数曲线预测

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

Mysql数据库基础操作

Mysql数据库 基本概念 内核的作用&#xff1a;调用硬件资源 数据库的作用 使用数据库可以高效且条理分明地存储数据&#xff0c;使人们能够更加迅速、方便的管理数据。 数据、表、数据库 数据 描述事物的符号记录&#xff0c;包括数字&#xff0c;文字&#xff0c;图形&…

nginx的正向代理和反向代理以及tomcat

nginx的正向代理和反向代理&#xff1a; 正向代理以及缓存配置&#xff1a; 代理&#xff1a;客户端不再是直接访问服务端&#xff0c;通过代理服务器访问服务端。 正向代理&#xff1a;面向客户端&#xff0c;我们通过代理服务器的IP地址访问目标范围端。 服务端只知道代理…

开发个人Go-ChatGPT--3 服务拆分

开发个人Go-ChatGPT–3 服务拆分 个人Go-ChatGPT项目可拆分用户服务&#xff08;user&#xff09;&#xff0c;AI模型服务&#xff08;AiModel&#xff09;&#xff0c;… 每个服务都可以再分为 api 服务和 rpc 服务。api 服务对外&#xff0c;可提供给 app 调用。rpc 服务是…

如何利用算法优化广告效果

效果广告以超过67%的占比&#xff0c;成为了中国互联网广告预算的大头。在BAT、字节等大的媒体平台上&#xff0c;效果广告以CPC实时竞价广告为主。在这种广告产品的投放中&#xff0c;广告主或其代理公司通过针对每个广告点击出价&#xff0c;系统自动把这些点击出价换算成eCP…

Java + MySQL 实现存储完整 Json

Java MySQL 实现存储完整 Json 一、应用场景二、数据库配置三、后端代码配置1、maven 依赖2、实体类3、Service 实现类4、xml 文件 四、测试1、新增接口2、查询接口3、数据表内容 一、应用场景 将前端传过来的 Json 完整存储到 MySQL 中&#xff0c;涉及技术栈为 Java、MyBat…

揭秘 Vue 组件通信:构建响应式数据流

引言 Vue.js 的核心特性之一是其组件化架构。组件化开发是一种现代的前端开发模式&#xff0c;它鼓励开发者将用户界面拆分成独立的、可复用的组件。每个组件都有自己的逻辑和结构&#xff0c;使得代码更加模块化&#xff0c;易于维护和测试。 Vue 组件基础 组件的定义和用途…

从资金管理的角度 谈谈伦敦金投资技巧

刚进入伦敦金市场的时候&#xff0c;笔者认为技术分析是很重要的&#xff0c;所以将学习伦敦金投资技巧的精力全部投入到技术分析的学习中。经过一系列交易的亏损&#xff0c;笔者才发现&#xff0c;其实交易管理才是最重要的。如果管理得好&#xff0c;30%的胜率&#xff0c;投…

docker-compose部署node-exporter

一、安装 node_exporter:image: prom/node-exporter:v1.8.0container_name: node_exportervolumes:- /proc:/host/proc:ro- /sys:/host/sys:ro- /:/rootfs:ro# ports:# - 9100:9100environment:TZ: Asia/Shanghaicommand:- --path.procfs/host/proc- --path.rootfs/rootfs- -…

数据机构记录顺序表-笔记1

一、线性表的基本概念 数据元素&#xff1a;线性表中的基本单位&#xff0c;每个元素都是线性表的一部分。 数据项&#xff1a;数据元素的具体值。 存储位置&#xff1a;线性表中的元素在内存中的具体存储位置。 线性表按存储结构可以分为顺序表和链表两大类&#xff1a; 1.1…

嵌入式C语言面试相关知识——关键字(不定期更新)

嵌入式C语言面试相关知识——关键字 一、博客声明二、C语言关键字1、sizeof关键字2、static关键字3、const关键字4、volatile关键字5、extern关键字 一、博客声明 又是一年一度的秋招&#xff0c;怎么能只刷笔试题目呢&#xff0c;面试题目也得看&#xff0c;想当好厂的牛马其实…

快速上手指南:使用 Minikube 在本地运行 Kubernetes 集群

前言 Minikube 是一个开源工具&#xff0c;用于在本地运行 Kubernetes 集群。它提供了一种简单的方法来在本地开发和测试 Kubernetes 应用程序&#xff0c;而无需设置完整的 Kubernetes 集群。以下是 Minikube 的基本使用步骤&#xff1a; 安装 Minikube 安装依赖项 虚拟化…

java之静态方法

如果要在类中使用方法&#xff0c;就得需要将这个类实例化。有时候希望在不创建对象的情况下&#xff0c;通过类名直接调用某个方法&#xff0c;就得需要静态方法&#xff0c;要实现静态方法&#xff0c;只需要再成员方法前加上static关键字 静态方法也可以通过类名和对象访问…

Charles拦截发送数据包-cnblog

Charles拦截发送数据包 打开允许断点 右键要打断点的数据包&#xff0c;打断点 重新发请求进入断点模式 修改完毕后发送

拦截HTTP的多种方式

部分场景下需要修改请求报文信息&#xff0c;可以利用 AOP 思维&#xff08;切面编程&#xff09;&#xff0c;对请求进行拦截处理。Web 中有见的几种发送请求的方式&#xff1a; XMLHttpRequestfetchwindow.navigator.sendBeaconnew Imageservice worker 针对这几种不同的场…