看完书上的栈不过瘾,为什么不动手试试呢?

news2024/9/22 7:30:17

一.栈的基本概念

1.栈的定义

(Stack):是只允许在一端进行插入或删除的线性表。首先栈是一种线性表,但限定这种线性表只能在某一端进行插入和删除操作

其中注意几点:

栈顶(Top):线性表允许进行插入删除的那一端。

栈底(Bottom):固定的,不允许进行插入和删除的另一端。

空栈:不含任何元素的空表。

栈又称为后进先出(Last In First Out)的线性表,简称LIFO结构

2.栈的常见基本操作

/ 支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{
    STDataType* _a;
    int _top;        // 栈顶
    int _capacity;  // 容量 
}Stack;
// 初始化栈 
void StackInit(Stack* ps); 
// 入栈 
void StackPush(Stack* ps, STDataType data); 
// 出栈 
void StackPop(Stack* ps); 
// 获取栈顶元素 
STDataType StackTop(Stack* ps); 
// 获取栈中有效元素个数 
int StackSize(Stack* ps); 
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
int StackEmpty(Stack* ps); 
// 销毁栈 
void StackDestroy(Stack* ps); 

二.栈的顺序存储结构

1.栈的顺序存储

采用顺序存储的栈称为顺序栈,它利用一组地址连续的存储单元存放自栈底到栈顶的数据元素,同时附设一个指针(top)指示当前栈顶元素的位置。

若存储栈的长度为StackSize,则栈顶位置top必须小于StackSize。当栈存在一个元素时,top等于0,因此通常把空栈的判断条件定位top等于-1。

当然我们也可以把top初始化成零,这样top指针就指向栈顶的下一个元素,只不过我们在实现的时候依然是通过指针的偏移量来对栈顶的元素来进行访问,所以两种初始化都是可以的,都是先存数据在移动指针。

2.顺序栈的基本算法

#pragma once
#include <stdbool.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

typedef int STDatatype;
typedef struct Stack
{
    STDatatype* a;
    int capacity;
    int top;   // 初始为0,表示栈顶位置下一个位置下标
}ST;

void StackInit(ST* ps);
void StackDestroy(ST* ps);
void StackPush(ST* ps, STDatatype x);
void StackPop(ST* ps);
STDatatype StackTop(ST* ps);

bool StackEmpty(ST* ps);
int StackSize(ST* ps);

3.顺序栈的实现

#include "Stack.h"

void StackInit(ST* ps)
{
    assert(ps);

    //ps->a = NULL;
    //ps->top = 0;
    //ps->capacity = 0;

    ps->a = (STDatatype*)malloc(sizeof(STDatatype) * 4);
    if (ps->a == NULL)
    {
        perror("malloc fail");
        exit(-1);
    }

    ps->top = 0;
    ps->capacity = 4;
}

void StackDestroy(ST* ps)
{
    assert(ps);

    free(ps->a);
    ps->a = NULL;
    ps->top = ps->capacity = 0;
}

void StackPush(ST* ps, STDatatype x)
{
    assert(ps);

    // 
    if (ps->top == ps->capacity)
    {
        STDatatype* tmp = (STDatatype*)realloc(ps->a, ps->capacity * 2 * sizeof(STDatatype));
        if (tmp == NULL)
        {
            perror("realloc fail");
            exit(-1);
        }

        ps->a = tmp;
        ps->capacity *= 2;
    }

    ps->a[ps->top] = x;
    ps->top++;
}

// 20:20
void StackPop(ST* ps)
{
    assert(ps);
    assert(!StackEmpty(ps));

    ps->top--;
}

STDatatype StackTop(ST* ps)
{
    assert(ps);
    assert(!StackEmpty(ps));

    return ps->a[ps->top - 1];
}

bool StackEmpty(ST* ps)
{
    assert(ps);

    /*if (ps->top == 0)
    {
        return true;
    }
    else
    {
        return false;
    }*/
    return ps->top == 0;
}

int StackSize(ST* ps)
{
    assert(ps);
    return ps->top;
}

4.测试程序

#include"stack.h"
void test(void)
{
    ST ST1;
    StackInit(&ST1);
    StackPush(&ST1, 1);
    StackPush(&ST1, 2);
    StackPush(&ST1, 3);
    StackPush(&ST1, 4);
    while (!StackEmpty(&ST1))
    {
        printf("%d\n", StackTop(&ST1));
        StackPop(&ST1);
    }
    StackDestroy(&ST1);
}
int main()
{
    test();
}

三.栈的链式存储结构

  1. 链栈

和顺序表一样,针对顺序栈的缺点,我们可以设计出链栈,采用链式存储的栈称为链栈,链栈的优点是便于多个栈共享存储空间和提高其效率,且不存在栈满上溢的情况。通常采用单链表实现,并规定所有操作都是在单链表的表头进行的。这里规定链栈没有头节点,指针Lhead指向栈顶元素,如下图所示。

2.链栈的定义

typedef struct Stack
{
    Datetype x;//数据域
    ST *next   // 指针域
}ST;

3.性能分析

链栈的进栈push和出栈pop操作都很简单,时间复杂度均为O(1)。

对比一下顺序栈与链栈,它们在时间复杂度上是一样的,均为O(1)。对于空间性能,顺序栈需要事先确定一个固定的长度,可能会存在内存空间浪费的问题,但它的优势是存取时定位很方便,而链栈则要求每个元素都有指针域,这同时也增加了一些内存开销,但对于栈的长度无限制。所以它们的区别和线性表中讨论的一样,如果栈的使用过程中元素变化不可预料,有时很小,有时非常大,那么最好是用链栈,反之,如果它的变化在可控范围内,建议使用顺序栈会更好一些。

四.共享栈(节省空间)

1.共享栈概念

利用栈底位置相对不变的特征,可让两个顺序栈共享一个一维数组空间,将两个栈的栈底分别设置在共享空间的两端,两个栈顶向共享空间的中间延伸,如下图所示:

两个栈的栈顶指针都指向栈顶元素,top0=-1时0号栈为空,top1=MaxSize时1号栈为空;仅当两个栈顶指针相邻(top0+1=top1)时,判断为栈满。当0号栈进栈时top0先加1再赋值,1号栈进栈时top1先减一再赋值出栈时则刚好相反。

2.设计一个共享栈

/*两栈共享空间结构*/
#define MAXSIZE 50  //定义栈中元素的最大个数
typedef DataType int;   //ElemType的类型根据实际情况而定,这里假定为int
/*两栈共享空间结构*/
typedef struct{
    DataType a[MAXSIZE];
    int top0;    //栈0栈顶指针
    int top1;    //栈1栈顶指针
}SqDoubleStack;

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

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

相关文章

2023年新三板产品及服务研究报告

第一章 概述 全国中小企业股份转让系统&#xff08;英语&#xff1a;National Equities Exchange and Quotations&#xff0c;缩写NEEQ&#xff09;&#xff0c;简称股转系统&#xff0c;是第三家全国性证券交易场所&#xff0c;因挂牌企业均为高科技企业而不同于原转让系统内…

软件测试12

一 Linux命令的共通知识点 1.通配符的使用 通配符&#xff1a;又叫文件名替换符号&#xff0c;符号具备特殊含义&#xff0c;例如&#xff1a;文件名&#xff1a;test&#xff0c;通配符可以写成???或者* *&#xff1a;代表可以匹配任意长度的文件名&#xff08;all所有&am…

xxl-job registry fail

解决方法&#xff1a; 1、检查nacos是否正确&#xff0c;一定要注意格式&#xff0c;一般都是addersses的地址问题&#xff0c;一定的要加/不然找不到&#xff0c;本机就不要使用ip了&#xff0c;用localhost。 xxl: job: admin: addresses: http://localhost:8080/xxl-job-ad…

【java】 java开发中 常遇到的各种难点 思路方案

文章目录逻辑删除如何建立唯一索引唯一索引失效问题加密字段模糊查询问题maven依赖冲突问题&#xff08;jar包版本冲突问题&#xff09;sql in条件查询时 将结果按照传入顺序排序作为一个开发人员 总会遇到各种难题 本文列举博主 遇见/想到 的例子 &#xff0c;也希望同学们可以…

【LVGL移植】STM32F1基于STM32CubeMX配置硬件SPI驱动1.8寸TFT ST7735S跑LVGL图形demo

【LVGL移植】STM32F1基于STM32CubeMX配置硬件SPI驱动1.8寸TFT ST7735S屏幕跑LVGL图形demo&#x1f3ac;运行LVGL 按键组件demo ✨基于STM32CubeMX配置工程是因为方便移植&#xff0c;只要是STM32芯片&#xff0c;拿到我的这个工程源码就可以根据自己的stm32芯片&#xff0c;自…

操作系统复试

2017软学 给出操作系统的定义&#xff0c;分别从资源管理&#xff0c;任务调度&#xff0c;用户接口等三个方面论述操作系统的职能 操作系统是位于硬件层之上、所有其他系统软件层之下的一个系统软件&#xff0c;使得管理系统中的各种软件和硬件资源得以充分利用&#xff0c;方…

MATLAB——求连续系统的响应

题目&#xff1a; 已知RC一阶高通电路图的系统函数H(s)为 H(s)UR(S)U(S)RRR1SCsRCsRC1H(s)\frac {UR(S)}{U(S)}R\frac {R}{R\frac {1}{SC}}\frac {sRC}{sRC1}H(s)U(S)UR(S)​RRSC1​R​sRC1sRC​ 其中&#xff1a;R200Ω &#xff0c;C0.47μF 。求其幅度频率响应与相位频率响应…

公网NAT网关与VPC NAT网关介绍与实践

NAT网关介绍 NAT网关是一种网络地址转换服务&#xff0c;提供NAT代理&#xff08;SNAT和DNAT&#xff09;能力。 公有云NAT分为公网NAT网关和VPC NAT网关。 1&#xff09;公网NAT网关&#xff1a;提供公网地址转换服务。 2&#xff09;VPC NAT网关&#xff1a;提供私网地址转换…

商品获价API调用说明:获取商品历史价格信息 代码分享

接口名称&#xff1a;item_history_price公共参数名称类型必须描述keyString是调用key&#xff08;获取测试key&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_search,item_get,item_search_shop等]cacheString…

Linux磁盘空间占满了

Linux服务器没有安装很多东西&#xff0c;但是硬盘空间爆满了。。。 df -h 查看硬盘空间&#xff0c;发现使用了99%。 刚开始以为是日志文件的占用的&#xff0c;删除了linux日志文件&#xff0c;发现作用不大&#xff0c;只多了几G。 不妨试试下面的命令 lsof L1 发现了有个…

SQL技能 - 窗口函数

SQL技能 - 窗口函数1. 排序函数1.1. 不分组排序1.2. 分组排序2. 聚合函数实现滑动窗口计算2.1. 常用聚合函数2.2. 滑动行范围的常用表达2.3. 示例3. lag、lead函数求增长率&#xff08;同比、环比&#xff09;窗口函数表达式&#xff1a; function(arg) OVER ([PARTITION BY ex…

K8s kubectl 高效使用技巧,搞定批处理!

1.kubectl用法详解 1. kubectl语法 kubectl [command] [Type] [NAME] [flags] command: 子命令&#xff0c;用于操作kubernetes集群资源对象的命令&#xff0c;例如&#xff1a;create, delete, describe, get, apply等等 TYPE: 资源对象的类型&#xff0c;区分大小写&#…

可视化组件届的仙女‖蝴蝶结图、玫瑰环图、小提琴图

在上一篇内容中为大家介绍了几个堪称可视化组件届吴彦祖的高级可视化图表。既然帅哥有了&#xff0c;怎么能少得了美女呢&#xff1f;今天就为大家介绍几个可视化组件届的“美女姐姐”&#xff0c;说一句是组件届的刘亦菲不为过。蝴蝶结图蝴蝶结图因其形似蝴蝶结而得名&#xf…

SDL—安全培训

0x00 前言 软件开发团队的所有成员都必须接受适当的培训&#xff0c;了解安全基础知识以及安全和隐私方面的最新趋势。直接参与软件程序开发的技术角色人员&#xff08;开发人员、测试人员和程序经理&#xff09;每年必须参加至少一门特有的安全培训课程。 这个是微软针对安全培…

蓝牙耳机哪个戴的最舒服?久戴不累的蓝牙耳机推荐

在喧嚣的时代中&#xff0c;快节奏和疲惫充斥着我们的生活&#xff0c;于是耳机成为了人们必不可少的东西&#xff0c;无论是闲暇时亦或是正处在工作时&#xff0c;都会将它戴上&#xff0c;出门在外戴耳机变成了常态&#xff0c;所以小编就整理了一期久戴不累的蓝牙耳机。 No…

【专项】112. 路径总和

112. 路径总和 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径&#xff0c;这条路径上所有节点值相加等于目标和 targetSum 。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 叶子节点 …

深度学习部署笔记(八): CUDA RunTime API-2.1Hello CUDA

1. CUDA Driver API和CUDA Runtime API CUDA Driver API和CUDA Runtime API都是用于访问GPU的API。它们之间的区别在于它们的功能和使用方法不同。 CUDA Driver API是一个底层的API&#xff0c;它提供了对GPU硬件的底层访问&#xff0c;以及GPU硬件的直接控制。使用Driver AP…

聊天机器人分析,它值不值得做?

如今&#xff0c;聊天机器人热度持续走高。在您的网站或社交媒体上设置它们比以往任何时候都容易。然而&#xff0c;相当多的公司也犯了同样的错误。他们非常热衷于尝试聊天机器人&#xff0c;但随后是时候提出一些重要问题了。我们的聊天机器人工作了吗&#xff1f;他们表现如…

Flutter面试题解析-GridView详解与应用

一、前言Flutter 作为时下最流行的技术之一&#xff0c;凭借其出色的性能以及抹平多端的差异优势&#xff0c;早已引起大批技术爱好者的关注&#xff0c;甚至一些 闲鱼 &#xff0c; 美团 &#xff0c; 腾讯 等大公司均已投入生产使用。虽然目前其生态还没有完全成熟&#xff0…

CAD如何绘制A0/A1/A2/A3/A4图框?

在CAD制图时&#xff0c;设计师一般会使用企业的定制图框模板或者个人的特色图框模板&#xff0c;让设计方案更加标准化、规范化。对于新人设计师而言&#xff0c;完成CAD制图已经非常头疼了&#xff0c;图框的绘制更是手忙脚乱。那么是否有更加高效的方式来完成A0、A1、A2、A3…