详解数据结构:栈

一、顺序栈

顺序栈的存储方式如下:

从图中可以看出,顺序栈需要两个指针,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,将栈顶元素赋给e

    return true;

}

4、取栈顶元素

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

完美图解:

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

代码实现:

int GetTop(SqStack S) //返回S的栈顶元素,栈顶指针不变

{

    if(S.top!=S.base)  //栈非空

        return *(S.top-1); //返回栈顶元素的值,栈顶指针不变

    else

        return -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;    //修改栈顶指针为p

    return 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;  //将栈顶元素赋给e

    p=S;  //用p保存栈顶元素地址,以备释放

    S=S->next;  //修改栈顶指针,指向下一个结点

    delete p;  //释放原栈顶元素的空间

    return true;

}

4.取栈顶元素

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

代码实现:

int GetTop(LinkStack S) //返回S的栈顶元素,不修改栈顶指针

{

    if(S!=NULL) //栈非空

        return S->data; //返回栈顶元素的值,栈顶指针不变

    else

        return -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,将栈顶元素赋给e
	return true;
}

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

int main()
{
	int n,x;
	SqStack S;
	InitStack(S);//初始化一个顺序栈S
	cout<<"请输入元素个数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;    //修改栈顶指针为p
	return true;
}

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

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

int main()
{
	int n,x;
	LinkStack S;
	InitStack(S);//初始化一个顺序栈S
	cout<<"请输入元素个数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.mfbz.cn/a/559664.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

8款不同的404页面(网站404页面必备)

第1款 部分代码 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <title>404</title><link rel"stylesheet" href"css/style.css"></head> <body><div cla…

C语言转型之路:从C到C++的类与对象初探

欢迎来CILMY23的博客 本篇主题为 C语言转型之路&#xff1a;从C到C的类与对象初探 个人主页&#xff1a;CILMY23-CSDN博客 个人专栏系列&#xff1a; Python | C语言 | 数据结构与算法 | C 感谢观看&#xff0c;支持的可以给个一键三连&#xff0c;点赞关注收藏。 写在前头…

hive搭建完整教学

目录 简介准备工作安装步骤&#xff08;一&#xff09;、下载hive包并解压到指定目录下&#xff08;二&#xff09;、设置环境变量&#xff08;三&#xff09;、下载MySQL驱动包到hive的lib目录下&#xff08;四&#xff09;、将hadoop的guava包拷贝到hive&#xff08;五&#…

美团财务科技Java后端一面:面向对象、类加载过程、全限定类名相同的类是否可以同时被加载

更多大厂面试内容可见 -> http://11come.cn 美团财务科技Java后端一面&#xff1a;面向对象、类加载过程、全限定类名相同的类是否可以同时被加载 如何理解面向对象&#xff1f; 面向对象 是具有对象概念的编程范式&#xff0c;面向对象将程序实现分为了一个个独立的对象&…

cdh cm界面HDFS爆红:不良 : 该 DataNode 当前有 1 个卷故障。 临界阈值:任意。(Linux磁盘修复)

一、表现 1.cm界面 报错卷故障 检查该节点&#xff0c;发现存储大小和其他节点不一致&#xff0c;少了一块物理磁盘 2.查看该磁盘 目录无法访问 dmesg检查发现错误 dmesg | grep error二、解决办法 移除挂载 umount /data10 #可以移除挂载盘&#xff0c;或者移除挂载目…

WPS的bug问题(解决方法->换成office吧):表格数据和透视图数据不一致问题,多次尝试确定该bug

1.软件版本 2.问题描述 我在原始表中对其中一列进行筛选&#xff0c;选择95%以上这个选项值&#xff0c;343个数据。 在筛选了95%以上这个选项之后&#xff0c;我的另一列的值全部是no&#xff0c;343个数据。 然后进行透视图之后&#xff0c;在绘制的图形中发现&#xff0c…

怎么压缩图片200k以下?压缩图片到指定大小

在工作中&#xff0c;会遇到在某些系统要上传照片&#xff0c;但是对于上传的照片大小有限制&#xff0c;比如限制大小不能超过200KB等&#xff0c;而外业拍摄的照片往往会超过限制的大小&#xff0c;那么这时就需要对照片进行压缩。尤其是我们在面对大量图片需要处理的时候&am…

一周IT资讯

又降了&#xff1f;运维4月平均月薪1W6&#xff1f; 薪资作为大部分人的主要收入来源&#xff0c;是每个人最关注的话题之一。 最近&#xff0c;小编搜索了近半年的运维薪资趋势&#xff0c;看看你的钱包缩水了没&#xff1f; *数据来自看准网 据了解&#xff0c;运维2024年…

Python 爬虫如何配置代理 IP (Py 采集)

在Python中配置代理IP&#xff0c;可以通过设置requests库的proxies参数来实现。以下是一个示例&#xff1a; import requests# 则立可以获取稳定代理Ip&#xff1a;https://www.kuaidaili.com/?refrg3jlsko0ymg # 推荐使用私密动态 IP proxies {"http": "ht…

Pulsar 社区周报 | No.2024-04-19 | Pulsar Meetup 深圳 2024 邀您报名

“ 各位热爱 Pulsar 的小伙伴们&#xff0c;Pulsar 社区周报更新啦&#xff01;这里将记录 Pulsar 社区每周的重要更新&#xff0c;周五发布。 ” Pulsar Meetup 深圳 2024 Pulsar Meetup 深圳 2024 将于 2024 年 4 月 27 日 周六举办&#xff0c;此次活动由 AscentStream 谙&a…

HR招聘测评,人才测评的方法有哪些?

各企业都需要人才&#xff0c;如果招聘不到合适的人才&#xff0c;就会对自身的发展带来极大的限制&#xff0c;很难找到自己的一席之地。一个优秀的人才&#xff0c;通常会成为许多公司争先哄抢的对象&#xff0c;在招聘过程中会成为一个香饽饽。但是要选出一个优秀的人才&…

戴尔电脑怎么关闭开机密码?

1.同时按键盘上是“window键”&#xff08;一般是键盘最下面一排第二个&#xff09;和“R键“&#xff0c;并在弹出的窗口输入“netplwiz”然后确定。 2.然后会弹出的“用户账户”窗口&#xff0c;接下来取消勾选“要使用本计算机&#xff0c;用户必须输入用户名和密码” 3.上面…

C语言---贪吃蛇(一)---准备工作

文章目录 前言1.Win32 API介绍1.1.Win32 API1.2. 控制台程序1.3.控制台屏幕上的坐标[COORD](https://learn.microsoft.com/zh-cn/windows/console/coord-str)1.4.[GetStdHandle](https://learn.microsoft.com/zh-cn/windows/console/getstdhandle)1.5.[GetConsoleCursorInfo](h…

运动想象 (MI) 分类学习系列 (9) :FBCNet

运动想象分类学习系列:FBCNet 0. 引言1. 主要贡献2. 提出的方法2.1 滤波器组卷积网络2.2 方差层结构介绍 3. 实验结果3.1 基线方法比较3.2 方差层对结果的影响3.3 脑卒中患者在相关模型中观察到更大的受试间变异性 4. 总结欢迎来稿 论文地址&#xff1a;https://arxiv.org/abs/…

详细UI色彩搭配方案分享

UI 配色是设计一个成功的用户界面的关键之一。UI 配色需要考虑品牌标志、用户感受、应用程序的使用场景&#xff0c;这样可以帮助你创建一个有吸引力、易于使用的应用程序。本文将分享 UI 配色的相关知识&#xff0c;帮助设计师快速构建 UI 配色方案&#xff0c;以满足企业的需…

什么是IoT?

什么是IoT&#xff1f; IoT&#xff0c;即物联网&#xff08;Internet of Things&#xff09;&#xff0c;是通过信息传感设备和互联网将各种物品连接起来&#xff0c;实现智能化的识别、定位、跟踪、监控和管理的网络系统。 以下是关于IOT的一些详细解释&#xff1a; 基本概…

【RAG 论文】面向知识库检索进行大模型增强的框架 —— KnowledGPT

论文&#xff1a;KnowledGPT: Enhancing Large Language Models with Retrieval and Storage Access on Knowledge Bases ⭐⭐⭐⭐ 复旦肖仰华团队工作 论文速读 KnowledGPT 提出了一个通过检索知识库来增强大模型生成的 RAG 框架。 在知识库中&#xff0c;存储着三类形式的知…

记录一下flume中因为taildir_position.json因位置不对导致数据无法从kafka被采到hdfs上的问题

【背景说明】 我需要用flume将kafka上的数据采集到hdfs上&#xff0c;发现数据怎么到不了hdfs。 【问题排查】 1.kafka上已有相应的数据 2.我的flume配置文档&#xff08;没问题&#xff09;&#xff0c; 3.时间拦截器&#xff08;没问题&#xff09;&#xff0c; 4.JSONObje…

DNS域名系统(Domain Name System)基础知识

目录 1.定义 2.DNS系统组成 3.DNS系统作用 4.域名系统命名规则 5.记录类型 6.DNS查询过程 7.DNS查询方式 8.DNS文件 1.定义 DNS系统是一个分布式的主机信息数据库&#xff0c;采用客户机/服务器模式。 域名系统&#xff08;英文&#xff1a;Domain Name System&#xf…

Python中的设计模式与最佳实践

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 Python中的设计模式与最佳实践 在软件开发中&#xff0c;设计模式是一种解决常见问题的经过…