9-数据结构-栈(C语言版)

数据结构-栈(C语言版)

目录

数据结构-栈(C语言版)

1.栈的基础知识

1.入栈,出栈的排列组合

        情景二:Catalan函数(计算不同出栈的总数)

2.栈的基本操作

        1.顺序存储

        (1)顺序栈-定义:

        (2)顺序栈-栈空

        (3)顺序栈-入栈

        (4)顺序栈-出栈以及取值

        (5)共享栈

        2.链式存储

        (1)链栈-定义:

        (2)链栈-入栈

        (3)链栈-出栈

        (4)链栈-打印栈

总代码如下:(可运行)



1.栈的基础知识

 简介:

        栈是后进先出,逻辑上相当于一个桶,只能从顶端操作。

1.入栈,出栈的排列组合

        情景一:已知入栈序列,求出栈序列的可能。

        方法:先看出栈序列最左边,之后按个排序,拿着这个出栈的数,取入栈序列找它前面的可能,之后再回到选择取对比。

        例如:a,b,c,d,e,f依次进栈,求出栈的可能不是哪个:一般为选择题,从选项中的出栈序列最左边开始找,如fedcba,若f先出栈,则f后面的次序一定是...e..d..c..b..a,发现符合,再看第二个fe,e出栈后,后面出栈的可能为d..c..b..a..f符合,再看第三个fed,d出栈后,可能出栈的有:c..b..a..,符合,直到最后都符合。所以这个出栈对。又例如:出栈序列cabdef,先c,c先出栈,后面可能..b..a,结果选项出栈为..a..b,次序反了,所以这个就不是,

        情景二:Catalan函数(计算不同出栈的总数)

        n个元素依次进栈,可以得到多少种不同的出栈序列?

        Catalan函数公式:\frac{C_{2n}^{n}\textrm{}}{n+1},别问为啥,问就是,记着就行了。代入,即可得到结果,

2.栈的基本操作

 简介:按照不同存储方式,分为顺序存储和链式存储。

        1.顺序存储

        简介:顺序存储即定义一个结构体,里面有一个存储数据的数组,和一个记录栈顶的变量top。

如图:

        (1)顺序栈-定义:

#define MaxSize 50  //最大容量
typedef struct
{int data[MaxSize];//存储栈数据的一维数组int top;	//表示栈顶的变量top
}SqStack;

        (2)顺序栈-栈空

        简介:要看清楚栈空时,top指向哪里,不同的指向,进栈出栈的操作就不一样,不过,一般画图,就明白了。

        初始化:InitStack(&s) 即栈空

//初始化
//因为想要改变结构体内的值,实参形参都变化,所以传栈s的地址进来,栈*S指针接收
void InitStack(SqStack *s)  
{s->top=-1;
} 

要看清top栈空的条件时什么,再进行相应的初始化。

初始化之后,便是验证是否栈空StackEmpty(s)

//判断是否栈空
void StackEmpty(SqStack s)
{if(s.top== -1)return 1;
}

        (1)s.top==-1,表示栈空

        

        此时,我的数组要想赋值,肯定需要top先加1,定位到数组第一个元素,随后再赋值。因此当top==-1表示空时,top先++,随后再赋值,top始终指向栈顶位置

         (2)s.top==0,表示栈空

         此时,我的数组要想赋值,top已经指向数组第一个位置,可以直接赋值,之后再top++。因此当top==0表示空时,先赋值,再top++,top始终指向栈顶位置的下一个位置

        (3)顺序栈-入栈

        入栈即从外边,进桶里,此时要考虑上溢情况,避免数组容量不够。上溢可通过一定的策略优化,减少上溢的情况

               代码如下:SqPush(&s,x);

//入栈
void SqPush(SqStack *s,int x)
{if(s->top == MaxSize-1){exit(-1);//栈满,退出 }s->top++;s->data[s->top]=x;	
} 

        (4)顺序栈-出栈以及取值

        出栈则是从顶部出取,只可操作一端。出栈时考虑下溢,下溢时逻辑错误,不取决于策略的优化

代码如下:

//出栈
void Sqpush(SqStack *s,int *n)
{if(s->top==-1)exit(-1); *n=s->data[s->top];s->top--;
} 

        (5)共享栈

        简介:当顺序栈一次性申请的数组空间太大时,会造成空间浪费,最后还有好多空间没有用。因此对于两个类型相同的栈,我们可以让他们在同一个栈中,进行存取。分别从左右两端进行入栈,中间为栈底。

        共享栈的好处:节省存储空间,降低发生上溢的可能

 栈空:top0==-1,top1==MaxSize

 栈满:他俩碰头了,top0+1=top1

共享栈了解思想即可。

        2.链式存储

         简介:采取单链表形式实现的栈,为栈的链式存储,只不过这里的单链表,只能从表头进行插入和删除。

        采用链栈的优点:便于多个栈共享存储空间,提高效率,不存在上溢情况,插入删除更方便。

        特殊约定:采用单链表实现的栈,默认没有头节点,头指针直接指向第一个实际结点,都在表头进行操作。

        (1)链栈-定义:

//栈的链式存储
typedef struct StackNode
{int data;struct StackNode *next;	}StackNode; 

        (2)链栈-入栈

思路:插入结点,插入结点先主动,P结点的指针与,存储原第一个结点的地址,即头节点所存的地址。之后更新头指针,把p结点地址赋值给头指针phead

 代码如下:

//入栈
StackNode*  StackNodepush(StackNode *phead,int x)
{StackNode* p=(StackNode*)malloc(sizeof(StackNode));p->data=x;p->next=NULL;if(phead==NULL){phead=p;}else{p->next=phead;phead=p; }return phead;
}

        (3)链栈-出栈

        出栈,即用一个变量接收出栈的值,随后再定义一个临时指针,指向需要出的结点,用来最后释放掉,之后移动头指针,更新头指针为第二个结点地址,最后释放掉出栈结点即可。

代码如下:

//出栈
StackNode* StackNodepop(StackNode* phead,int x)
{	//单链表可能为空,所以需要先判断非法情况 if(phead==NULL)return NULL;//取第一结点的值 x=phead->data;//另外赋值第一个结点 ,为了后面找到它并释放 StackNode *p=phead;//直接更新头节点 phead=p->next;free(p);return phead;
} 

        (4)链栈-打印栈

void StackPrint(StackNode* phead)
{StackNode* pos =phead;while(pos!=NULL){printf("%d->",pos->data);pos = pos->next;}printf("NULL\n");} 

总代码如下:(可运行)

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//顺序栈
#define MaxSize 50
typedef struct
{int data[MaxSize];int top;	
}SqStack;
//初始化
void InitStack(SqStack *s)
{s->top=-1;
} 
//判断是否栈空
int StackEmpty(SqStack s)
{if(s.top== -1)return 1;
}
//入栈
void SqPush(SqStack *s,int x)
{if(s->top == MaxSize-1){exit(-1);//栈满,退出 }s->top++;s->data[s->top]=x;	
} 
//出栈
void Sqpush(SqStack *s,int *n)
{if(s->top==-1)exit(-1); *n=s->data[s->top];s->top--;
} 
//栈的链式存储
typedef struct StackNode
{int data;struct StackNode *next;	}StackNode; 
//入栈
StackNode*  StackNodepush(StackNode *phead,int x)
{StackNode* p=(StackNode*)malloc(sizeof(StackNode));p->data=x;p->next=NULL;if(phead==NULL){phead=p;}else{p->next=phead;phead=p; }return phead;
}
//出栈
StackNode* StackNodepop(StackNode* phead,int x)
{	//单链表可能为空,所以需要先判断非法情况 if(phead==NULL)return NULL;//取第一结点的值 x=phead->data;//另外赋值第一个结点 ,为了后面找到它并释放 StackNode *p=phead;//直接更新头节点 phead=p->next;free(p);return phead;
} 
void StackPrint(StackNode* phead)
{StackNode* pos =phead;while(pos!=NULL){printf("%d->",pos->data);pos = pos->next;}printf("NULL\n");} 
int main()
{StackNode *phead;phead=StackNodepush(phead,0);phead=StackNodepush(phead,1);phead=StackNodepush(phead,2);phead=StackNodepush(phead,3);StackPrint(phead);return 0;
} 

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

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

相关文章

c语言操作符

目录 运算符 移位操作符 左移操作符 右移操作符 位操作符 按位与& 按位或| 按位异或^ 异或交换数字 计算二进制中1的个数 关系操作符 逻辑操作符 条件操作符 逗号表达式 下标引用、函数调用和结构成员 隐式类型转换 整形提升实例&#xff1a; 算术转换 操作…

Java并发编程(四)线程同步 中 [AQS/Lock]

概述 Java中可以通过加锁&#xff0c;来保证多个线程访问某一个公共资源时&#xff0c;资源的访问安全性。Java提出了两种方式来加锁 第一种是我们上文提到的通过关键字synchronized加锁&#xff0c;synchronized底层托管给JVM执行的&#xff0c;并且在java 1.6 以后做了很多…

Flink窗口分类简介及示例代码

水善利万物而不争&#xff0c;处众人之所恶&#xff0c;故几于道&#x1f4a6; 文章目录 1. 流式计算2. 窗口3. 窗口的分类◆ 基于时间的窗口&#xff08;时间驱动&#xff09;1) 滚动窗口&#xff08;Tumbling Windows&#xff09;2) 滑动窗口&#xff08;Sliding Windows&…

ArcGIS Maps SDK for JavaScript系列之三:在Vue3中使用ArcGIS API加载三维地球

目录 SceneView类的常用属性SceneView类的常用方法vue3中使用SceneView类创建三维地球项目准备引入ArcGIS API创建Vue组件在OnMounted中调用初始化函数initArcGisMap创建Camera对象Camera的常用属性Camera的常用方法 要在Vue 3中使用ArcGIS API for JavaScript加载和展示三维地…

太牛了!国内版ChatDoc企业知识库,直接操作Doc、Docx、PDF、txt等文件

自ChatGPT问世以来&#xff0c;国外就有ChatPDF、ChatDOC等基于文档问答的项目&#xff0c;但是国内还一直处于对话类产品的研发中。 贵州猿创科技研发了基于本地向量模型的ChatDoc知识库系统&#xff0c;可以直接上传Doc、Docx、PDF、txt、网页链接等进行问答。 体验地址&…

【资讯速递】AI与人类思维的融合;OpenAI在中国申请注册“GPT-5”商标;移动大模型主要面向to B 智能算力是未来方向

2023年8月11日 星期五 癸卯年六月廿五 第000001号 欢迎来到爱书不爱输的程序猿的博客, 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 本文收录于IT资讯速递专栏,本专栏主要用于发布各种IT资讯&#xff0c;为大家可以省时省力的就能阅读和了解到行业的一些新资讯 资…

redis的基础命令01

1、操作库的指令 1、清除当前库---flushdb 2、清除所有库---flushAll 2、操作key的指令 最常用的指令get、set 1&#xff09;set key value 2&#xff09;get key 基础指令 1、del 删除单个&#xff1a;del key 、批量删除&#xff1a;del key1 key2 key3 2、exists 判断key是否…

1.作用域

1.1局部作用域 局部作用域分为函数作用域和块作用域。 1.函数作用域: 在函数内部声明的变量只能在函数内部被访问&#xff0c;外部无法直接访问。 总结&#xff1a; (1)函数内部声明的变量&#xff0c;在函数外部无法被访问 (2)函数的参数也是函数内部的局部变量 (3)不同函数…

Eclipse-配置彩色输出打印

文章目录 前言配置下载查看是否安装 前言 这是一篇古老的文章&#xff0c;那个时候还在用Eclipse &#xff0c;现在已经换 IDEA 了… 这是一篇 2018 年的文章&#xff0c;我只是将文章从个人比较挪到了CSDN 中 配置 配置完然后下载下面插件即可生成彩色代码。 下载 ANSI …

章节5:Burp 扫描功能

章节5&#xff1a;Burp 扫描功能 参考资料 https://portswigger.net/burp/documentation/scanner https://portswigger.net/burp/documentation/desktop/scanning 模块总体介绍&#xff1a; https://portswigger.net/burp/vulnerability-scanner 扫描功能的使用&#xff…

MEC | 条款3 绝对不要以多态(polymorphically)方式处理数组

条款3 绝对不要以多态&#xff08;polymorphically&#xff09;方式处理数组 文章目录 条款3 绝对不要以多态&#xff08;polymorphically&#xff09;方式处理数组继承Example 打印基类-派生类数组传入BalencedBST 数组到函数 删除基类-派生类数组>>>>> 欢迎关…

06 为什么需要多线程;多线程的优缺点;程序 进程 线程之间的关系;进程和线程之间的区别

为什么需要多线程 CPU、内存、IO之间的性能差异巨大多核心CPU的发展线程的本质是增加一个可以执行代码工人 多线程的优点 多个执行流&#xff0c;并行执行。&#xff08;多个工人&#xff0c;干不一样的活&#xff09; 多线程的缺点 上下文切换慢&#xff0c;切换上下文典型值…