当前位置: 首页 > news >正文

顺序栈和链式栈

顺序栈和链式栈

我们之前讲过表其实就是元素和元素1:1的关系,从而又衍生出两种存储结构顺序表和链式表。

但是我们会发现如果对一个结构不加以约束其实这个结构也就越没有意思,这就像自由一样,没有约束的自由带来的只可能是毁灭。

那么我们因该如何去约束一个表呢,其实很简单,如果我们插入删除只能在一端操作,那我们可以将这一个结构称做栈结构那如果插入删除只能在两端操作,我们称这样的结构为队列。

受制于篇幅的原因,这篇文章主要讲的就是栈

栈是什么

其实栈很简单,大家应该都见过羽毛球桶吧

如果羽毛球桶只能用一边拿出和放入你会如何做

在这里插入图片描述

那肯定是一个个放进去,那拿出来也一样,你只有一个口最后进的肯定先出,最先进的肯定后出。

很好你已经抓到栈的精髓了,就一句话

先入后出

很简单吧?

那我们不经要想想这个结构又有啥用

  • 历史记录

我们经常会用到返回的按钮来恢复我们的历史记录,这其实就是将你的历史操作压入到你自己定义的栈中,然后当你需要恢复的时候就进行弹出操作

  • 记录轨迹

像一些小的机器人是如何根据判断进行返回的呢?其实也是用了栈的操作,当你遇到障碍物的时候,就会返回原来的位置进行重新的判断,使得小机器人可以走到一条正确的路上。

好滴,我们了解了栈的应用,现在来构思一下如何去实现这个结构

其实有两种方法一种是顺序表来实现的,而另一种是链表来实现的,我们挨个讲一下

顺序表实现

顺序表肯定要先规定一个大小以免溢出了

而如果在定义结构的话将大小也定义进去其实这样更加的方便

如图

在这里插入图片描述

最下面是对栈使用数量的记录

我们可以这样定义(伪代码)

struct stack
{element data[10];int pos;
};
//初始化一下
struct stack a1;
a1.pos=0;

好的我们要进行压入操作了

好的好玩的来了

其实我们的压栈有四种压法

满栈,空栈(二选一)

递增,递减(二选一)

这四个词组成的四个方法

递增空栈
a1.data[a1.pos]=e;
a1.pse++;递增满栈
a1.pos++;
a1.data[a1.pos]=e;递减满栈
a1.pos--;
a1.data[a1.pos]=e;递减空栈
a1.data[a1.pos]=e;
a1.pos--;

既然有四种压栈方法,那么自然有四种出栈的方法

出栈的方法要和入栈的方法一一对应

递增空栈
a1.pos--;
x=a1.data[a1.pos];递减满栈
x=a1.data[a1.pos];
a1.pos--;递减满栈
e=a1.data[a1.pos];
a1.pos++;递减空栈
a1.pos++;
e=a1.data[a1.pos];

理论讲完了我们来点实际的代码

顺序栈代码实现

结构定义与结构操作声明

#ifndef STACK_H
#define STACK_H
#include "common.h"
#define MaxStackSize 5
typedef int Element;
typedef struct  {Element data[MaxStackSize];int top;
}ArrayStack;
//递增空栈
void initArrayStack(ArrayStack *stack);//压入
void poshArrayStack(ArrayStack *stack,Element data);
//弹出
void pushArrayStack(ArrayStack *stack);Element getArrayStack(const ArrayStack *stack);//判空与判满
int isEmptyArrayStack(const ArrayStack *stack);
int isFullArrayStack(const ArrayStack *stack);
#endif //STACK_H

对结构操作的实现

#include "Stack.h"#include <string.h>//递增空栈void initArrayStack(ArrayStack *stack) {memset(stack, 0, sizeof(ArrayStack));stack->top = 0;
}void poshArrayStack(ArrayStack *stack, Element data) {stack->data[stack->top] = data;++stack->top;
}void pushArrayStack(ArrayStack *stack) {--stack->top;
}Element getArrayStack(const ArrayStack *stack) {int pos=stack->top-1;return stack->data[pos];
}int isEmptyArrayStack(const ArrayStack *stack) {return stack->top == 0;
}int isFullArrayStack(const ArrayStack *stack) {return stack->top==MaxStackSize;
}

测试

void text1() {ArrayStack infor;initArrayStack(&infor);for (int i = 1; i <= 5; i++) {poshArrayStack(&infor,i+100);}printf("push 5 number\n");if (!isFullArrayStack(&infor)) {poshArrayStack(&infor,5);}//采用弹栈操作,一个一个弹Element w;while (!isEmptyArrayStack(&infor)) {w=getArrayStack(&infor);printf("\t %d ",w);pushArrayStack(&infor);}
}

结果

在这里插入图片描述

学完了顺序栈,我们再来看看链式栈

链式栈

顾名思义,链式链式,以链表的方式来实现栈,那么我们又应该如何实现呢?

其实链表,就两个重点,删除和添加,你要如何删除和添加才能满足我们所需要的结构,这是我们要首先思考清楚的。

好的我们回到栈这个话题

我们是否可以用向前增加的方式来完成入栈呢?

如下图

在这里插入图片描述

不行!为啥?因为你这个入栈操作简单了,那你的出栈操作如何处理。

既然正向不行,我们在后面添加节点再试试
在这里插入图片描述

把头节点往新节点一指

new_node->next=top;
top=new_node;

正好符合栈先进后出的条件,操作起来也方便

再来一删除

tmp=top;
top=top->next;
free(tmp);

好咧齐活

注意一点

我们画的图其实有缺陷,如果你真的用指针的话可能面临一个尴尬的问题

如下

void insert(node*top,element e)
{new_node=xxx;new_node->next=top;top=new_node;//仔细的看看这句话
}

这最后一句显然改变不了,如果改变还要用二级指针,我们可以选择来定义一个新节点节点来解决这个问题。

void insert(LinkStack*stack,element e)
{new_node=xxx;new_node=next=top;stack->top=new_node;
}

这样就解决了

链式栈的代码实现

结构定义与结构操作的声明

#ifndef LINKSTACK_H
#define LINKSTACK_H
#include "common.h"
#include "Stack.h"typedef struct _node {Element data;struct _node *next;
}StackNode;typedef struct {StackNode *top;int count;
}LinkStack;
//初始化
LinkStack* createLinkStack();void releaseLinkStack(LinkStack* stack);int pushLinkStack(LinkStack* stack, Element element);
int popLinkStack(LinkStack* stack,Element* element);#endif //LINKSTACK_H

结构操作的实现


#include "LinkStack.h"
#include <stdio.h>
#include <stdlib.h>LinkStack * createLinkStack() {LinkStack*linkstack = (LinkStack*)malloc(sizeof(LinkStack));if (linkstack == NULL) {printf("Memory allocation failed\n");return NULL;}linkstack->top=NULL;linkstack->count=0;return linkstack;}
//释放
void releaseLinkStack(LinkStack *stack) {if (stack) {while (stack->top) {StackNode * tmp = stack->top;stack->top = tmp->next;free(tmp);stack->count--;}printf("released link stack\n");}}int pushLinkStack(LinkStack *stack, Element element) {StackNode *node = (StackNode*)malloc(sizeof(StackNode));if (node == NULL) {printf("Memory allocation failed\n");return -1;}node->data = element;node->next = stack->top;stack->top = node;++stack->count;return 0;
}int popLinkStack(LinkStack *stack, Element *element) {if (stack->top == NULL) {return -1;}*element = stack->top->data;StackNode *tmp = stack->top;stack->top=tmp->next;free(tmp);--stack->count;return 0;}

测试

void text2() {LinkStack*stak=createLinkStack();if (stak==NULL) {return;}for (int i = 1; i <= 5; i++) {pushLinkStack(stak,i);}printf("have%d\n",stak->count);Element w;while (popLinkStack(stak,&w)!=-1) {printf("\t %d ",w);}releaseLinkStack(stak);
}

测试结果

在这里插入图片描述

好滴我的这篇博客到这里就结束了,喜欢记得点点赞哦(๑′ᴗ‵๑)I Lᵒᵛᵉᵧₒᵤ❤

http://www.lryc.cn/news/580380.html

相关文章:

  • spring加载外部properties文件属性时,读取到userName变量值和properties文件的值不一致
  • 动手实践OpenHands系列学习笔记8:后端服务开发
  • 大数据在UI前端的应用探索:基于用户行为分析的产品优化策略
  • [论文阅读] 软件工程 | 可持续性标志在问答平台中的应用
  • 基于matlab卡尔曼滤波器消除噪声
  • [前缀和+多重背包]3333. 找到初始输入字符串 II
  • JMM--数据原子操作
  • 【深圳大学机器学习】实验一:PCA算法
  • Qt窗口被外部(非Qt内部机制)强制销毁,第二次再重复使用不显示
  • cloudflare配合github搭建免费开源影视LibreTV一个独享视频网站 详细教程
  • vue3 el-input el-select 非空校验
  • 每日学习问题记录
  • DVWA靶场通关笔记-验证码绕过reCAPTCHA(High级别)
  • vue中添加原生右键菜单
  • 【零基础学AI】第24讲:卷积神经网络(CNN)架构设计
  • 【无标题】Go语言中的反射机制 — 元编程技巧与注意事项
  • 3dmax物理材质转换标准材质,物理材质转VR材质,VR材质转标准材质3dmax物理材质转标准材质插件
  • 电脑休眠设置
  • c++ python 共享内存
  • 后端树形结构
  • STM32F103RCTx的PWM输出控制电机
  • js游戏简单修改
  • React Native 开发环境搭建--mac--android--奔溃的一天
  • Hinge×亚矩云手机:以“深度连接”为名,重构云端社交的“真实感”
  • CSS02:四种CSS导入方式
  • pyspark大规模数据加解密优化实践
  • Python小工具之PDF合并
  • 数据结构:多维数组在内存中的映射(Address Mapping of Multi-dimensional Arrays)
  • IDEA中application.yml配置文件不自动提示解决办法
  • 如何在IntelliJ IDEA中设置数据库连接全局共享