顺序栈和链式栈

顺序栈和链式栈

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

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

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

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

栈是什么

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

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

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

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

先入后出

很简单吧?

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

  • 历史记录

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

  • 记录轨迹

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

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

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

顺序表实现

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

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

如图

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

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

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

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

好的好玩的来了

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

满栈,空栈(二选一)

递增,递减(二选一)

这四个词组成的四个方法

c 复制代码
递增空栈
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--;

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

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

c 复制代码
递增空栈
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];

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

顺序栈代码实现

结构定义与结构操作声明

c 复制代码
#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

对结构操作的实现

c 复制代码
#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;
}

测试

c 复制代码
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);
    }
}

结果

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

链式栈

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

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

好的我们回到栈这个话题

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

如下图

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

既然正向不行,我们在后面添加节点再试试

把头节点往新节点一指

c 复制代码
new_node->next=top;
top=new_node;

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

再来一删除

c 复制代码
tmp=top;
top=top->next;
free(tmp);

好咧齐活

注意一点

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

如下

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

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

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

这样就解决了

链式栈的代码实现

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

c 复制代码
#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

结构操作的实现

c 复制代码
#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;

}

测试

c 复制代码
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ᵒᵛᵉᵧₒᵤ❤

相关推荐
weixin_437398213 分钟前
转Go学习笔记(2)进阶
服务器·笔记·后端·学习·架构·golang
is081539 分钟前
STM32的 syscalls.c 和 sysmem.c
c语言·stm32·嵌入式硬件
张人玉1 小时前
C# 常量与变量
java·算法·c#
teeeeeeemo1 小时前
回调函数 vs Promise vs async/await区别
开发语言·前端·javascript·笔记
学不动CV了1 小时前
数据结构---链表结构体、指针深入理解(三)
c语言·arm开发·数据结构·stm32·单片机·链表
weixin_446122462 小时前
LinkedList剖析
算法
百年孤独_3 小时前
LeetCode 算法题解:链表与二叉树相关问题 打打卡
算法·leetcode·链表
我爱C编程3 小时前
基于拓扑结构检测的LDPC稀疏校验矩阵高阶环检测算法matlab仿真
算法·matlab·矩阵·ldpc·环检测
算法_小学生3 小时前
LeetCode 75. 颜色分类(荷兰国旗问题)
算法·leetcode·职场和发展
运器1233 小时前
【一起来学AI大模型】算法核心:数组/哈希表/树/排序/动态规划(LeetCode精练)
开发语言·人工智能·python·算法·ai·散列表·ai编程