详解数据结构:栈

一、顺序栈

顺序栈的存储方式如下:

从图中可以看出,顺序栈需要两个指针,base指向栈底,top指向栈顶。

typedef struct SqStack {ElemType *base; //栈底指针ElemType *top; //栈顶指针}SqStack;

说明:

ElemType是元素类型,需要什么类型就写什么类型。

typedef将结构体等价于类型名Sqstack。

栈定义好了之后,还要先定义一个最大的分配空间,这和数组一样,需要预先分配空间,因此可以采用宏定义:

#define Maxsize 100;  //预先分配空间,这个数值根据实际需要预估确定

上面的结构体定义采用了动态分配的形式,也可以采用静态分配的形式,使用一个长数组存储数据元素,一个整型下标记录栈顶元素的位置。静态分配的顺序栈结构定义如下:

typedef struct SqStack {ElemType data[Maxsize]; //定长数组int top; //栈顶下标}SqStack;

注意:栈只能在一端操作,后进先出,是人为规定的,也就是说不允许在中间查找,取值,插入,删除等操作。顺序栈本身是顺序存储的,有人就想:我偏要从中间取一个元素,这也是可以的,但这样做,这就不是栈了。

1、顺序栈的初始化

初始化一个空栈,动态分配Maxsize大小的空间,用S.top和S.base指向该空间的基地址。

代码实现:

bool InitStack(SqStack &S) //构造一个空栈S{S.base=new int[Maxsize];//为顺序栈分配一个最大容量为Maxsize的空间if(!S.base)    //空间分配失败return false;S.top=S.base;  //top初始为base,空栈return true;}

2、入栈

入栈前要判断是否栈满,如果栈已满,则入栈失败;否则将元素放入栈顶,栈顶指针向上移动一个位置(top++)。

图解:

输入1,入栈(左图)

接着输入2,入栈(右图)

代码实现:

bool Push(SqStack &S,int e) // 插入元素e为新的栈顶元素{if(S.top-S.base==Maxsize) //栈满return false;*(S.top++)=e; //元素e压入栈顶,然后栈顶指针加1,等价于*S.top=e; S.top++;return true;}

3、出栈

出栈前要先判断是否为空栈,如果栈是空的,则出栈失败;否则将栈顶元素暂存给一个变量,栈顶指针向下移动一个位置(top--)。

完美图解:

栈顶元素所在的位置是S.top-1,因此把该元素取出来,暂存在变量e中,然后S.top指针向下移动一个位置。因此可以先移动一个位置,即--S.top,然后再取出元素。

例:栈顶元素4出栈前后的状态

注意:因为顺序栈删除一个元素时,并没有销毁该空间,所以4其实还在那个位置,只不过下一次再有元素进栈时,就把他覆盖了。相当于该元素已出栈,因为栈的内容时S.base到S.top-1。

代码实现:

bool Pop(SqStack &S,int &e) //删除S的栈顶元素,暂存在变量e中{if(S.base==S.top) //栈空return false;e=*(--S.top); //栈顶指针减1,将栈顶元素赋给ereturn true;}

4、取栈顶元素

取栈顶元素和出栈不同。取栈顶元素只是把栈顶元素复制一份,栈顶指针未移动,栈内元素个数未变。而出栈时栈顶指针向下移动一个位置,栈内不在包含这个元素。

完美图解:

取栈顶元素*(S.top-1)即元素4,取值后S.top指针没有改变,栈内元素的个数也没有改变。

代码实现:

int GetTop(SqStack S) //返回S的栈顶元素,栈顶指针不变{if(S.top!=S.base)  //栈非空return *(S.top-1); //返回栈顶元素的值,栈顶指针不变elsereturn -1;}

二、链栈

栈可以顺序存储,也可以用链式存储。

顺序栈是分配一段连续的空间,需要两个指针:base指向栈底,top指向栈顶,而链栈每个节点的地址都不连续,只需要一个栈顶指针即可。

链栈的每个节点都包含两个域:数据域和指针域。可以把链栈看作一个不带头结点的单链表,但只能在头部进行插入、删除、取值等操作,不可以在中间和尾部操作。

链栈的结构体定义如下:

typedef struct Snode{ElemType data; //数据域struct Snode *next; //指针域,指向下一个节点的指针}Snode,*LinkStack;

链栈的节点定义和单链表一样,只不过它只能在栈顶那一端操作而已。

1、链栈的初始化

初始化一个空的链栈是不需要头结点的,因此只需要让栈顶指针为空即可。

代码实现:

typedef struct Snode{ElemType data; //数据域struct Snode *next; //指针域,指向下一个节点的指针}Snode,*LinkStack;

2.入栈

入栈是将新元素节点压入栈顶。因为链栈中第一个节点为栈顶,因此将新元素节点插入到第一个节点的前面,然后修改栈顶指针指向新结点即可。有点像堆柴,将新的节点堆在栈顶之上,新的节点成为新的栈顶。

完美图解:

(1)生成新结点。入栈前要创建一个新结点,将元素e存入该结点的数据域。

代码实现:

p=new Snode; //生成新结点,用p指针指向该结点p->data=e; //将e放在新结点数据域

(2)将新元素节点插入到第一个节点的前面,然后修改栈顶指针指向新结点。

赋值解释:

  • p->next=S; //将新结点的指针域指向S,即将S的地址赋值给新结点的指针域。
  • S=p;    //修改栈顶指针为p

整体代码实现:

bool Push(LinkStack &S,int e) //在栈顶插入元素e{LinkStack p;p=new Snode; //生成新结点p->data=e; //将e放在新结点数据域p->next=S; //将新结点的指针域指向S,即将S的地址赋值给新结点的指针域S=p;    //修改栈顶指针为preturn true;}

3.出栈

出栈就是把栈顶元素删除,绕过指针指向下一个节点,然后释放该结点空间。

赋值解释:

  • p=S;  //用p保存栈顶元素地址,以备释放
  • S=S->next;  //修改栈顶指针,指向下一个结点
  • delete p;  //释放原栈顶元素的空间

代码实现:

bool Pop(LinkStack &S,int &e) //删除S的栈顶元素,用e保存其值{LinkStack p;if(S==NULL) //栈空return false;e=S->data;  //将栈顶元素赋给ep=S;  //用p保存栈顶元素地址,以备释放S=S->next;  //修改栈顶指针,指向下一个结点delete p;  //释放原栈顶元素的空间return true;}

4.取栈顶元素

取栈顶元素和出栈不同,取栈顶元素只是把栈顶元素赋值一份,栈顶指针并没有改变。而出栈是指删除栈顶元素,栈顶指针指向了下一个元素。

代码实现:

int GetTop(LinkStack S) //返回S的栈顶元素,不修改栈顶指针{if(S!=NULL) //栈非空return S->data; //返回栈顶元素的值,栈顶指针不变elsereturn -1;}

顺序栈和链栈的所以基本操作都只需要常数事件,所以在事件效率上难分伯仲。在空间效率方面,顺序栈需要预先分配固定长度的空间,有可能造成空间浪费或溢出;链栈每次只分配一个节点,除非没有内存,否则不会出现溢出,但是每个节点需要一个指针域,结构性开销增加。因此,如果元素个数变化较大,可以采用栈链;反之,可以采用顺序栈。在实际中,顺序栈比链栈应用更广泛。

配套完整代码(顺序栈):

#include<iostream>
using namespace std;#define Maxsize 100  //预先分配空间,这个数值根据实际需要预估确定;typedef struct SqStack {int *base; //栈底指针int *top; //栈顶指针
}SqStack;bool InitStack(SqStack &S) //构造一个空栈S
{S.base=new int[Maxsize];//为顺序栈分配一个最大容量为Maxsize的空间if(!S.base)    //空间分配失败return false;S.top=S.base;  //top初始为base,空栈return true;
}bool Push(SqStack &S,int e) // 插入元素e为新的栈顶元素
{if(S.top-S.base==Maxsize) //栈满return false;*(S.top++)=e; //元素e压入栈顶,然后栈顶指针加1,等价于*S.top=e; S.top++;return true;
}bool Pop(SqStack &S,int &e) //删除S的栈顶元素,暂存在变量e中
{if(S.base==S.top) //栈空return false;e=*(--S.top); //栈顶指针减1,将栈顶元素赋给ereturn true;
}int GetTop(SqStack S) //返回S的栈顶元素,栈顶指针不变
{if(S.top!=S.base)  //栈非空return *(S.top-1); //返回栈顶元素的值,栈顶指针不变elsereturn -1;
}int main()
{int n,x;SqStack S;InitStack(S);//初始化一个顺序栈Scout<<"请输入元素个数n:"<<endl;cin>>n;cout<<"请依次输入n个元素,依次入栈:"<<endl;while(n--){cin>>x; //输入元素Push(S,x);}cout<<"元素依次出栈:"<<endl;while(S.top!=S.base)//如果栈不空,则依次出栈{cout<<GetTop(S)<<"\t";//输出栈顶元素Pop(S,x);   //栈顶元素出栈}return 0;
}

配套完整源代码(链栈):

#include<iostream>
using namespace std;typedef struct Snode{int data; //数据域struct Snode *next; //指针域
}Snode,*LinkStack;bool InitStack(LinkStack &S)//构造一个空栈S
{S=NULL;return true;
}bool Push(LinkStack &S,int e) //在栈顶插入元素e
{LinkStack p;p=new Snode; //生成新结点p->data=e; //将e放在新结点数据域p->next=S; //将新结点的指针域指向S,即将S的地址赋值给新结点的指针域S=p;    //修改栈顶指针为preturn true;
}bool Pop(LinkStack &S,int &e) //删除S的栈顶元素,用e保存其值
{LinkStack p;if(S==NULL) //栈空return false;e=S->data;  //将栈顶元素赋给ep=S;  //用p保存栈顶元素地址,以备释放S=S->next;  //修改栈顶指针,指向下一个结点delete p;  //释放原栈顶元素的空间return true;
}int GetTop(LinkStack S) //返回S的栈顶元素,不修改栈顶指针
{if(S!=NULL) //栈非空return S->data; //返回栈顶元素的值,栈顶指针不变elsereturn -1;
}int main()
{int n,x;LinkStack S;InitStack(S);//初始化一个顺序栈Scout<<"请输入元素个数n:"<<endl;cin>>n;cout<<"请依次输入n个元素,依次入栈:"<<endl;while(n--){cin>>x; //输入元素Push(S,x);}cout<<"元素依次出栈:"<<endl;while(S!=NULL)//如果栈不空,则依次出栈{cout<<GetTop(S)<<"\t";//输出栈顶元素Pop(S,x);   //栈顶元素出栈}return 0;
}

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

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

相关文章

【智能算法】水循环算法(WCA)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2012年&#xff0c;H Eskandar等人受到自然水循环过程启发&#xff0c;提出了水循环算法&#xff08;Water Cycle Algorithm, WCA&#xff09;。 2.算法原理 2.1算法思想 WCA模拟了大自然水循环过…

稳态视觉诱发电位 (SSVEP) 分类学习系列 (1) :FFT-CNN-CCA

稳态视觉诱发电位分类学习系列:FFT-CNN-CCA 0. 引言1. 主要贡献2. 提出的方法2.1 数据处理2.2 卷积神经网络的结构 3. 结果3.1 健康参与者结果比较3.2 卒中患者结果比较 4. 总结欢迎来稿 论文地址&#xff1a;https://ieeexplore.ieee.org/document/8708243 论文题目&#xff1…

日志分析简单总结

1、分析日志的目的 误报&#xff1a;不是攻击而上报成攻击 漏报&#xff1a;是攻击而没有防御的情况 日志分析可以判断是否误判或者漏判&#xff0c;可以溯源攻击行为 在护网作为防守方必备的技能&#xff08;分析NGAF和态势感知&#xff0c;发现异常&#xff09; 2、攻击出现…

探索比特币符文热:市场趋势与持续性分析

在加密货币世界中&#xff0c;比特币一直是备受关注的焦点之一。然而&#xff0c;近年来&#xff0c;随着DeFi&#xff08;去中心化金融&#xff09;的兴起&#xff0c;一种新的潮流开始崭露头角——比特币符文。本文将探讨比特币符文的兴起&#xff0c;分析市场趋势&#xff0…

iOS 17上如何恢复数据?iOS 17 数据恢复软件

“您好&#xff0c;我正在为我的 iPhone 寻找一款iOS 17 数据恢复软件。升级到 iOS 17 后&#xff0c;我丢失了 iPhone 上的所有照片、联系人和消息。有什么建议吗&#xff1f;” ——丹尼 iOS 17数据恢复软件下载 升级到iOS 17后如何恢复丢失的数据&#xff1f;由于在 iPhone…

聊聊 Linux iowait

哈喽大家好&#xff0c;我是咸鱼。 我们在使用 top 命令来查看 Linux 系统整体 CPU 使用情况的时候&#xff0c;往往看的是下面这一列&#xff1a; %Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 68.0 wa, 0.0 hi, 0.0 si, 0.0 st其中&#xff0c;man 手册解释 wa 表示 …

异地组网、内部网络需求同时满足,贝锐企业路由器G300开箱体验

由于公司最近新增了办事处&#xff0c;作为IT管理员的我不仅需要搞定办事处的网络&#xff0c;还需要解决远程访问公司内部办公系统以及文件存储服务器的问题。 在此之前&#xff0c;只有少量人员出差时&#xff0c;我们采用了虚拟专网方案来进行远程访问。然而&#xff0c;新…

深度学习基础之《TensorFlow框架(15)—神经网络》

一、神经网络基础 1、什么是神经网络 人工神经网络&#xff08;Artificial Neural Network&#xff0c;简写为ANN&#xff09;。也简称为神经网络&#xff08;NN&#xff09; 是一种模仿生物神经网络&#xff08;动物的中枢神经系统&#xff0c;特别是大脑&#xff09;结构和功…

电脑虚拟机有免费的吗?常见的虚拟机工具软件有哪些?Parallels Desktop19最新版本好用吗

PD虚拟机&#xff0c;即Parallels Desktop&#xff0c;是一款专为Mac用户设计的虚拟机软件&#xff0c;由Parallels公司开发&#xff0c;它允许用户在Mac操作系统上无缝运行Windows、Linux以及其他操作系统&#xff0c;并在这些系统中安装程序或者游戏&#xff0c;无需重启即可…

MySQL权限管理大揭秘:用户、组、权限解析

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 MySQL权限管理大揭秘&#xff1a;用户、组、权限解析 前言用户和组的概念用户和组的概念创建和管理用户创建和管理角色 权限的类型和分配MySQL中的权限类型分配不同类型的权限给用户和组 权限验证与日…

Unity系统学习笔记

文章目录 1.基础组件的认识1.0.组件继承关系图1.1.项目工程文件结构&#xff0c;各个文件夹都是做什么的&#xff1f;1.2.物体变化组件1.2.3.三维向量表示方向1.2.4.移动物体位置附录&#xff1a;使用变换组件实现物体WASD移动 1.3.游戏物体和组件的显示和禁用1.3.1.界面上的操…

【Linux】实现一个进度条

我们之前也学了gcc/vim/make和makefile&#xff0c;那么我们就用它们实现一个进度条。 在实现这个进度条之前&#xff0c;我们要先简单了解一下缓冲区和回车和换行的区别 缓冲区其实就是一块内存空间&#xff0c;我们先看这样一段代码 它的现象是先立马打印&#xff0c;三秒后程…

《QT实用小工具·三十八》QT炫酷的菜单控件

1、概述 源码放在文章末尾 非常飘逸的 Qt 菜单控件&#xff0c;带有各种动画效果&#xff0c;用起来也十分方便。 无限层级&#xff0c;响应键盘、鼠标单独操作&#xff0c;支持单快捷键。 允许添加自定义 widget、layout&#xff0c;当做特殊的 QDialog 使用。 项目demo演示…

大数据学习第四天

文章目录 yaml 三大组件的方式交互流程hive 使用安装mysql(hadoop03主机)出现错误解决方式临时密码 卸载mysql (hadoop02主机)卸载mysql(hadoop01主机执行)安装hive上传文件解压解决版本差异修改hive-env.sh修改 hive-site.xml上传驱动包初始化元数据在hdfs 创建hive 存储目录启…

pytorch-MNIST测试实战

目录 1. 为什么test2. 如何做test3. 什么时候做test4. 完整代码 1. 为什么test 如下图&#xff1a;上下两幅图中蓝色分别表示train的accuracy和loss&#xff0c;黄色表示test的accuracy和loss&#xff0c;如果单纯看train的accuracy和loss曲线就会认为模型已经train的很好了&a…

23年新算法,SAO-SVM,基于SAO雪消融算法优化SVM支持向量机回归预测(多输入单输出)-附代码

SAO-SVM是一种基于SAO雪消融算法优化的支持向量机&#xff08;SVM&#xff09;回归预测方法&#xff0c;适用于多输入单输出的情况。下面是一个简要的概述&#xff0c;包括如何使用SAO-SVM进行回归预测的步骤&#xff1a; 步骤&#xff1a; 1. 数据准备&#xff1a; 收集并准…

勾八头歌之RNN

一、RNN快速入门 1.学习单步的RNN&#xff1a;RNNCell # -*- coding: utf-8 -*- import tensorflow as tf# 参数 a 是 BasicRNNCell所含的神经元数, 参数 b 是 batch_size, 参数 c 是单个 input 的维数&#xff0c;shape [ b , c ] def creatRNNCell(a,b,c):# 请在此添加代码…

sprinboot+人大金仓配置

1. .yml 配置 spring:datasource:type: com.alibaba.druid.pool.DruidDataSource#driverClassName: dm.jdbc.driver.DmDriver## todo 人大金仓driverClassName: com.kingbase8.Driverdruid:## todo 人大金仓master:url: jdbc:kingbase8://111.111.111.111:54321/dbname?cu…

粘合聚酰亚胺PI塑料材料使用UV胶的优势有哪些? (三十四)

聚酰亚胺PI难于粘接&#xff0c;在PI粘接方法中使用UV胶粘剂粘接PI的优势有哪些&#xff1f; 聚酰亚胺&#xff08;PI&#xff09;是一种具有耐高低温性能、高绝缘性、耐化性、低热膨胀系数的材料&#xff0c;广泛用于FPC基材和各种耐高温电机电器的绝缘材料。然而&#xff0c;…

MySQL常见的约束

什么是约束&#xff1f; 限制&#xff0c;限制我们表中的数据&#xff0c;保证添加到数据表中的数据准确和可靠性&#xff01;凡是不符合约束的数据&#xff0c;插入时就会失败&#xff0c;插入不进去的&#xff01; 比如&#xff1a;学生信息表中&#xff0c;学号就会约束不…