比特数据结构与算法(第三章_上)栈的概念和实现(力扣:20. 有效的括号)

news2024/12/29 11:03:12

一、栈(stack)

栈的概念:

① 栈是一种特殊的线性表,它只允许在固定的一端进行插入和删除元素的操作。

② 进行数据插入的删除和操作的一端,称为栈顶 。另一端则称为 栈底 。

③ 栈中的元素遵守后进先出的原则,即 LIFO原则(Last In First Out)。

压栈:栈的插入操作叫做 进栈 / 压栈 / 入栈 ,入数据在栈顶。

出栈:栈的删除操作叫做出栈。出数据也在栈顶。

两道栈的选择题:

1.一个栈的初始状态为空。现将元素1、2、3、4、5、A、B、C、D、E 依次入栈,

然后再依次出栈,则元素出栈的顺序是( )。

A 12345ABCDE

B EDCBA54321

C ABCDE12345

D 54321EDCBA

2.若进栈序列为 1,2,3,4 ,进栈过程中可以出栈,则下列不可能的一个出栈序列是( )。

A 1,4,3,2

B 2,3,4,1

C 3,1,4,2

D 3,4,2,1

答案:

1.A

2.c

栈的结构:

数组栈和链式栈

实现栈无非就两种结构:数组结构 和 链式结构,两种结构都可以实现。

数组栈和链式栈哪种结构更好?

相对而言数组的结构实现更优,尾插尾删的效率高,缓存利用率高,它的唯一缺点只是增容,

但是增容1次扩2倍对栈来说本身就比较合理,是无伤大雅的。而链式栈虽然不会空间浪费,

用一个 malloc 申请一个,但是链式栈存在一个致命的缺点:单链表不好出数据,

必须要实现双向链表,否则尾上删除数据将会异常麻烦。

如果硬要使用链式栈:

① 如果用尾做栈顶,尾插尾删,要设计成双向链表,否则删数据效率低。

② 如果用头做栈顶,头插头删,就可以设计成单链表。

本章栈的实现将采用数组结构

二、栈的定义

(数组栈和顺序表定义差不多)

静态栈

简单介绍下静态栈:

typedef char StackDataType;
#define N 10
 
typedef struct Stack 
{
StackDataType _array[N];  //数组
int _top;                 //栈顶
} Stack;

解读:N 给多了浪费给少了又不够用,所以静态栈在实际中是不实用的。静态栈满了就不能扩大了,

而动态栈是 malloc 出来的,不够了可以 realloc 扩容。虽然不实用,但是我们也得认识它,

知道有这么一个东西。

动态栈

本章将采用动态栈实现

typedef int StackDataType;

typedef struct Stack 
{
    StackDataType* array;  //数组
    int top;               //栈顶
    int capacity;          //容量
} Stack;

三、栈的实现(完整代码)

实现了顺序表和链表,栈的实现很简单,直接放完整代码了

Stack.h

#pragma once

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

typedef int StackDataType;

typedef struct Stack 
{
    StackDataType* array;  //数组
    int top;               //栈顶
    int capacity;          //容量
} Stack;

void StackInit(Stack* ps);//初始化
void StackDestroy(Stack* ps);//销毁
void StackPush(Stack* ps, StackDataType x);//进栈
bool StackEmpty(Stack* ps);//判断栈是否为空
void StackPop(Stack* ps);// 出栈
StackDataType StackTop(Stack* ps);//返回栈顶数据
int StackSize(Stack* ps);//返回栈的大小

Stack.c

#include "Stack.h"

void StackInit(Stack* ps)//初始化
{
    assert(ps);
    ps->array = NULL;
    ps->top = 0;  // ps->top = -1
    ps->capacity = 0;
}

void StackDestroy(Stack* ps)//销毁
{
    assert(ps);

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

void StackPush(Stack* ps, StackDataType x)//进栈
{
    assert(ps);
    if (ps->top == ps->capacity) 
    {
        int new_capacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
        StackDataType* tmp_arr =(StackDataType *) realloc(ps->array, sizeof(StackDataType) * new_capacity);
        if (tmp_arr == NULL) 
        {
            printf("realloc failed!\n");
            exit(-1);
        }
        // 更新
        ps->array = tmp_arr;
        ps->capacity = new_capacity;
    }

    ps->array[ps->top] = x;// 填入数据
    ps->top++;
}

bool StackEmpty(Stack* ps)//判断栈是否为空
{
    assert(ps);

    return ps->top == 0; //等于0就是空,就是真
}

void StackPop(Stack* ps)// 出栈
{
    assert(ps);
    //assert(ps->top > 0);  //防止top为空
    assert(!StackEmpty(ps));

    ps->top--;
}

StackDataType StackTop(Stack* ps)//返回栈顶数据
{
    assert(ps);
    //assert(ps->top > 0);  //防止top为空
    assert(!StackEmpty(ps));

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

int StackSize(Stack* ps) //计算栈的大小
{
    assert(ps);

    return ps->top;// 因为我们设定top是指向栈顶的下一个,所以top就是size
}

Test.c

#include "Stack.h"

void TestStack1() 
{
    Stack st;
    StackInit(&st);
    StackPush(&st, 1);
    StackPush(&st, 2);
    StackPush(&st, 3);
    StackPush(&st, 4);
    StackPush(&st, 4);

    StackPop(&st);
    StackPop(&st);
    StackPop(&st);
    StackPop(&st);
    //StackPop(&st);

    printf("%d", StackTop(&st));
    StackDestroy(&st);
}

void TestStack2() 
{
    // 入栈:1 2 3 4
    Stack st;
    StackInit(&st);
    StackPush(&st, 1);
    StackPush(&st, 2);
    StackPush(&st, 3);
    StackPush(&st, 4);

    // 出栈:4 3 2 1
    while (!StackEmpty(&st))
    {
        printf("%d ", StackTop(&st));
        StackPop(&st);
    }
    StackDestroy(&st);
}

void TestStack3() 
{
    // 入栈:1 2 3 4
    Stack st;
    StackInit(&st);
    StackPush(&st, 1);
    StackPush(&st, 2);
    StackPush(&st, 3);
    StackPush(&st, 4);

    // 提前出栈:4 3
    printf("%d ", StackTop(&st));
    StackPop(&st);
    printf("%d ", StackTop(&st));
    StackPop(&st);

    // 入栈:5  6
    StackPush(&st, 5);
    StackPush(&st, 6);

    // 出栈:6 5 2 1
    while (!StackEmpty(&st))
    {
        printf("%d ", StackTop(&st));
        StackPop(&st);
    }
    StackDestroy(&st);
}

int main() 
{
    //TestStack1();
    //TestStack2();
    TestStack3();
    return 0;
}

四、一道栈的OJ题:

力扣链接:20. 有效的括号

难度简单

给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。

  1. 左括号必须以正确的顺序闭合。

  1. 每个右括号都有一个对应的相同类型的左括号。

示例 1:

输入:s = "()"

输出:true

示例 2:

输入:s = "()[]{}"

输出:true

示例 3:

输入:s = "(]"

输出:false

提示:

  • 1 <= s.length <= 104

  • s 仅由括号 '()[]{}' 组成

bool isValid(char * s){

}

解析代码:

这道题用C++写就很简单,用C语言写就需要创建一个栈。(可以用数组什么的,但不好)

我们刚写了一个栈,直接把Stack.h和Stack.c复制粘贴过去,把头文件删掉,

再把typedef int StackDataType; 改成typedef char StackDataType;

typedef char StackDataType;

typedef struct Stack 
{
    StackDataType* array;  //数组
    int top;               //栈顶
    int capacity;          //容量
} Stack;

void StackInit(Stack* ps);
void StackDestroy(Stack* ps);
void StackPush(Stack* ps, StackDataType x);
bool StackEmpty(Stack* ps);
void StackPop(Stack* ps);
StackDataType StackTop(Stack* ps);
int StackSize(Stack* ps);

void StackInit(Stack* ps)//初始化
{
    assert(ps);
    ps->array = NULL;
    ps->top = 0;  // ps->top = -1
    ps->capacity = 0;
}

void StackDestroy(Stack* ps)//销毁
{
    assert(ps);

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

void StackPush(Stack* ps, StackDataType x)//进栈
{
    assert(ps);
    if (ps->top == ps->capacity) 
    {
        int new_capacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
        StackDataType* tmp_arr =(StackDataType *) realloc(ps->array, sizeof(StackDataType) * new_capacity);
        if (tmp_arr == NULL) 
        {
            printf("realloc failed!\n");
            exit(-1);
        }
        // 更新
        ps->array = tmp_arr;
        ps->capacity = new_capacity;
    }

    ps->array[ps->top] = x;// 填入数据
    ps->top++;
}

bool StackEmpty(Stack* ps)//判断栈是否为空
{
    assert(ps);

    return ps->top == 0; //等于0就是空,就是真
}

void StackPop(Stack* ps)// 出栈
{
    assert(ps);
    //assert(ps->top > 0);  //防止top为空
    assert(!StackEmpty(ps));

    ps->top--;
}

StackDataType StackTop(Stack* ps)//返回栈顶数据
{
    assert(ps);
    //assert(ps->top > 0);  //防止top为空
    assert(!StackEmpty(ps));

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

int StackSize(Stack* ps) //计算栈的大小
{
    assert(ps);

    return ps->top;// 因为我们设定top是指向栈顶的下一个,所以top就是size
}

bool isValid(char* s) {
    Stack st;
    StackInit(&st);
    while (*s)
    {
        if ((*s == '(') || (*s == '[') || (*s == '{'))
        {
            StackPush(&st, *s);
        }
        else
        {
            //栈是空,且遇到右括号了,栈里面没有左括号
            if (StackEmpty(&st))
            {
                StackDestroy(&st);
                return false;
            }

            StackDataType top = StackTop(&st);
            StackPop(&st);

            if ((top == '(' && *s != ')')
                || (top == '[' && *s != ']')
                || (top == '{' && *s != '}'))
            {
                StackDestroy(&st);
                return false;
            }
        }
        s++;
    }
    //如果栈不是空,说明还有左括号没出完,不合题意
    //此时StackEmpty返回false,相反,栈是空,返回true
    bool ret = StackEmpty(&st);
    StackDestroy(&st);
    return ret;
}

本篇完,下一篇:队列

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

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

相关文章

推荐系统[三]:粗排算法常用模型汇总(集合选择和精准预估),技术发展历史(向量內积,WideDeep等模型)以及前沿技术

1.前言:召回排序流程策略算法简介 推荐可分为以下四个流程,分别是召回、粗排、精排以及重排: 召回是源头,在某种意义上决定着整个推荐的天花板;粗排是初筛,一般不会上复杂模型;精排是整个推荐环节的重中之重,在特征和模型上都会做的比较复杂;重排,一般是做打散或满足…

Android OTA 相关工具(一) 虚拟 A/B 之 snapshotctl

Android 虚拟 A/B 分区推出快三年了&#xff0c;不论是 google 还是百度结果&#xff0c;除了源代码之外&#xff0c;竟然没有人提到这个 Android Virtual A/B 的调试工具 &#xff0c;着实让人感觉意外。 所以我相信还有不少人不知道 Android OTA 到底都有哪些调试工具&#…

【React】react-router 路由详解

&#x1f6a9;&#x1f6a9;&#x1f6a9; &#x1f48e;个人主页: 阿选不出来 &#x1f4a8;&#x1f4a8;&#x1f4a8; &#x1f48e;个人简介: 一名大二在校生,学习方向前端,不定时更新自己学习道路上的一些笔记. &#x1f4a8;&#x1f4a8;&#x1f4a8; &#x1f48e;目…

力扣-查找重复的电子邮箱

大家好&#xff0c;我是空空star&#xff0c;本篇带大家了解一道简单的力扣sql练习题。 文章目录前言一、题目&#xff1a;182. 查找重复的电子邮箱二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交SQL运行结果总结…

物联网对供应链管理的影响

物联网对于许多行业来说都是一项革命性技术&#xff0c;其应用领域涉及零售、交通、金融、医疗保健和能源等行业。物联网在供应链等流程中已经展示了其深度的潜力。管理、预测和监督应用程序有助于车队运输经理提高配送的运营效率&#xff0c;并增加决策的准确性。如今&#xf…

网络服务与应用

14.1网络服务与应用概述 14.2实验一&#xff1a;FTP 1、实验环境&#xff1a;如图&#xff0c;AR1作为FTP sever、AR2作为FTP client &#xff0c;实现AR1与AR2之间的文件传输。 2、实验拓扑&#xff1a; 3、实验步骤&#xff1a; 步骤1&#xff1a;配置设备ip地址 AR1: …

固定值电阻的检测方法总结

🏡《总目录》 目录 1,概述2,测量方法3,检测方法3.1,读值3.2,测量3.3,排故4,总结1,概述 本文简单总结固定值电阻的测量与检查方法要点和注意事项。 2,测量方法 对于固定值电阻的测量来讲,直接将万用表红黑表笔分别插入到如下图所示的红色和黑色接线端。然后将万用表…

【MySQL】MySQL表的增删改查(进阶)

✨个人主页&#xff1a;bit me&#x1f447; ✨当前专栏&#xff1a;MySQL数据库&#x1f447; ✨算法专栏&#xff1a;算法基础&#x1f447; ✨每日一语&#xff1a;悟已往之不谏&#xff0c;知来者之可追。实迷途其未远&#xff0c;觉今是而昨非。 目 录&#x1f384;一. 数…

黑马点评项目总结(未完待续)

黑马点评项目总结0. 整体架构1. 短信登录模块1.1 基于session&#xff08;1&#xff09;后台发送验证码Code&#xff08;2&#xff09;登录、注册&#xff08;3&#xff09;校验登录状态1.2 基于Redis&#xff08;1&#xff09;后台发送验证码Code&#xff08;2&#xff09;登录…

ur3+robotiq ft sensor+robotiq 2f 140配置rviz仿真环境

ur3robotiq ft sensorrobotiq 2f 140配置rviz仿真环境 搭建环境&#xff1a; ubuntu: 20.04 ros: Nonetic sensor: robotiq_ft300 gripper: robotiq_2f_140_gripper UR: UR3 在安装sensor和gripper之前&#xff0c;先简单配置一下UR机械臂的仿真环境&#xff0c;可参考这篇博…

零入门kubernetes网络实战-16->使用golang给docker环境下某个容器里添加一个额外的网卡

《零入门kubernetes网络实战》视频专栏地址 https://www.ixigua.com/7193641905282875942 本篇文章视频地址(稍后上传) 上一篇文章&#xff0c;我们使用了golang在veth pair链接的网络命名空间里添加了网卡&#xff0c; 本篇文章&#xff0c;我尝试&#xff0c;在docker环境下…

新建idea项目

目录IDEA系列之创建各种项目 https://blog.csdn.net/LOVEQD123/article/details/105886077 idea 创建项目的三种方式 https://blog.csdn.net/weixin_50034122/article/details/118754521 创建空项目 https://blog.csdn.net/qq_44537956/article/details/123075134 创建 spri…

百度百科词条怎么做?百度百科词条创建攻略分享

只要是想要将自己宣传出去的企业或是个人&#xff0c;都建议创建属于自己的百度百科词条&#xff0c;因为百度百科词条流量大、权重高、排名靠前&#xff0c;创建百度百科词条可以提高企业或是个人的知名度和口碑。 百度百科词条怎么做&#xff1f;每天都有用户在百度上搜索这…

携手亚马逊云科技,大地量子高精度功率预测系统助力清洁能源消纳提速增效

近年来&#xff0c;我国光伏和风电并网装机容量持续增长&#xff0c;截至2021年底&#xff0c;全国可再生能源装机规模突破10亿千瓦&#xff0c;占总发电装机容量的44.8%。其中&#xff0c;风电装机3.28亿千瓦、光伏发电装机3.06亿千瓦。风光电总装机和新增装机规模多年来位居全…

图解 script 标签中的 async 和 defer 属性

图解 script 标签中的 async 和 defer 属性 我们在工作中经常会碰到 script 标签,一般会有以下三种形式 <script srcxxx></script> <script srcxxx async></script> <script srcxxx defer></script>那么这三种形式的 script 标签有什么区…

java 多线程

1.什么是进程&#xff1f;什么是线程&#xff1f; 进程是:一个应用程序&#xff08;1个进程是一个软件&#xff09;。 线程是&#xff1a;一个进程中的执行场景/执行单元。 注意&#xff1a;一个进程可以启动多个线程。 我们在启动java程序的时候&#xff0c;会先启动JVM&am…

【2】MYSQL数据的导入与导出

文章目录 MYSQL-库(相同库名称)的导入导出MYSQL-库(不同库名称)的导入导出MYSQL-表的导入导出MYSQL-表的指定查询记录导入导出前提: 客户端工具是:SQLyog MYSQL-库(相同库名称)的导入导出 1、选中指定库——右键,选择【将数据库复制到不同的主机/数据库】 2、选中指…

分布式之Raft共识算法分析

写在前面 在分布式之Paxos共识算法分析 一文中我们分析了paxos算法&#xff0c;知道了其包括basic paxos和multi paxos&#xff0c;并了解了multi paxos只是一种分布式共识算法的思想&#xff0c;而非具体算法&#xff0c;但可根据其设计具体的算法&#xff0c;本文就一起来看…

SORT与DeepSORT简介

一、MOT( mutil-object tracking)步骤 在《DEEP LEARNING IN VIDEO MUTIL-OBJECT TEACKING: A SURVEY》这篇基于深度学习多目标跟踪综述中&#xff0c;描绘了MOT问题的四个主要步骤 1.跟定视频原始帧 2.使用目标检测器如Faster-rcnn, YOLO, SSD等进行检测&#xff0c;获取目标…

vue 3.0 Vue Router导航守卫的使用

目录前言&#xff1a;安装路由快速使用1. 创建路由模块2.规定路由模式3.使用路由规则4.声明路由链接和占位符5.重定向路由6.嵌套路由7.路径参数8. 声明式和编程式导航8.1 导航到不同的位置8.2 替换当前位置8.3 路由历史9.导航守卫9.1 全局前置守卫9.2全局路由守卫的语法参数9.3…