草庐IT

数据结构练习题之栈与队列:括号匹配问题(C语言实现)

术业还未专攻 2023-10-27 原文

     这只是其中一个例题,看完我对这道题的分析之后,关于括号匹配的问题你肯定能够掌握个差不多。转载请注明本文链接!

目录

一、问题描述

二、问题分析 

三、代码实现

(一)、定义结构体

(二)、初始化栈

(三)、进栈函数

(四)、判断栈是否为空

(五)、出栈函数

(六)、获取栈顶元素

(七)、主函数

(八)、运行结果

 四、完整代码


一、问题描述

Description

 给你一串字符,不超过50个字符,可能包括括号、数字、字母、标点符号、空格,你的任务是检查这一串字符中的( ) ,[ ],{ }是否匹配。

Input

 输入数据有多组,处理到文件结束。

Output

 如果匹配就输出“yes”,不匹配输出“no”

Sample

Input (输入)

sin(20+10)
{[}]

Output(输出)

yes
no

二、问题分析 

       这是一道让我做了三天才做出来的题,只能说我太**,把简单的问题想的过于复杂了。那我们来分析一下括号匹配问题我们需要做什么,我们需要注意什么。

(1)、首先看到括号匹配问题,我们需要一个栈,这个栈是用来存储算术表达式中的左括号'(','{','['的。

(2)、在存储左括号时,我们需要判断一下栈是否已满,只要栈不满我们就可以把它直接压入到栈中。

(3)、当我们遇到右括号时,我们需要看一下当前栈中是否有元素,如果栈是空的,那么我们就不用判断下去了,直接结束程序,括号是不匹配的;如果栈中有元素,那我们我们就拿出来栈顶元素,与当前我们遇到的右括号进行匹配,如果他们是一对,那么我们就把当前栈中的左括号出栈,继续扫描算术表达式,循环执行第(2)个步骤和第(3)个步骤;如果不是一对,那么我们也不用继续下去了,直接结束程序,括号是不匹配的。

(4)、我们要知道括号是成对出现的,有左括号无右括号,有右括号无左括号,这都是不行的。需要注意的是:当我们判断括号是否匹配时,不能把栈顶的括号和当前的右括号是否相等作为判断条件。因为左括号和右括号肯定是不相等的。我们只能判断一下当前右括号是哪一种括号,然后我们手动的定义出它对应的左括号,用这个我们定义的左括号和栈顶括号进行是否相等的判断。

(5)、对于这道题来说,当我们遇到'\0'时才停止扫描,之所以是‘\0',是因为数组存储完毕后,系统会自动的在末尾加上'\0'用来标记数组存储到这里就结束了。否则一直扫描算数表达式中的括号。

(6)、扫描完算术表达式之后,我们要看一下当前栈中是否还有元素,如果没有元素了,说明括号匹配,如果栈中还有元素,说明不匹配。因为我们遇到匹配的括号就执行出栈操作,全部匹配的话,到最后栈中的元素应该是都栈了的。

三、代码实现

(一)、定义结构体

       根据我们对栈的了解,我们要先定义一个结构体,这个结构体中有一个数组用于存储元素,还有一个栈顶标记位top。因为栈是后进先出的。我们只需要一个栈顶标记位就可以对这个栈进行进栈出栈判空等的操作。如果对栈的只是不够熟悉,请先看完有关栈的知识再接着往下看。

#include <stdio.h>
#include <stdlib.h>
#define Maxsize 100   //数组大小
typedef struct ST
{
    char data[Maxsize]; //存储栈中的元素
    int  top;           //栈顶标记位
}Stack;                 //用Stack来表示这个结构体

(二)、初始化栈

       因为数组的下标是从0开始的,刚开始我们并没有存元素,那我们让top==-1即可。当存入元素的时候,让top+1,然后在它标记的位置存储元素即可。

void Init(Stack *L)
{
    L->top=-1;
}

(三)、进栈函数

void Push(Stack *L,char x)
{
    if(L->top>=Maxsize)     //当我们栈满的时候就不能存储元素了
    {
        return;
    }
    L->top++;               //让top先加一
    L->data[L->top]=x;       //在top标记的位置存储当前的元素x
}

(四)、判断栈是否为空

int Empty(Stack L)
{
    if(L.top==-1)
    {
        return 1;//为空返回1
    }
    return 0;    //不为空返回0
}

(五)、出栈函数

        出栈的时候只需判断栈是否为空,如果不为空,那就让栈顶标记位top-1即可。

void Pop(Stack *L)
{
    if(L->top==-1)
    {
        return;
    }
    L->top--;
}

(六)、获取栈顶元素

       当我们遇到右括号的时候,我们就需要获取栈顶的元素了,来判断栈顶元素是否和当前右括号匹配。

char Get(Stack L)
{
    return L.data[L.top];
}

(七)、主函数

         我们上面定义的函数都很简单,主要是看我们在主函数中如何去调用上面这些函数,在什么情况下我们才能用到上面的函数。

int main()
{
    Stack L;                                       //定义一个栈
    char s[100];                                   //定义一个字符数组用来存储我们输入的算术表达式
    while(gets(s))                                  //用来获得我们输入的各个字符,包括空格
    {
        Init(&L);                                  //我们先初始化栈L
        int flag=1;                                //这个变量用来标记括号是否匹配成功
        for(int i=0;s[i]!='\0';i++)                //循环遍历我们输入的算术表达式中的括号
        {          
            if(s[i]=='('||s[i]=='['||s[i]=='{')    //如果是左括号我们就看能不能让它入栈
            {
                if(L.top<Maxsize)                  //栈没满我们就让左括号进栈,调用Push函数
                {
                    char x=s[i];
                    //进栈
                    Push(&L,x);
                }

            }
            else if(s[i]==')')                      //如果栈是这个右括号,就判断栈是否为空
            {
                if(Empty(L))                        //栈为空,我们就标记flag=0,结束循环,括号不匹配
                {
                    flag=0;
                    break;
                }
                else                                 //栈不空,我们就获取栈顶元素,调用Get函数
                {
                    if(Get(L)=='(')                  //括号匹配了,调用Pop函数,将左括号出栈
                    {
                        Pop(&L);
                    }
                    else                              //括号不匹配,那我们标记flag=0,结束循环,括号不匹配
                    {
                        flag=0;
                        break;
                    }
                }
            }
            else if(s[i]=='}')                           //接下来的两个else  if和上面的思想一致。
            {

                if(Empty(L))
                {
                    flag=0;
                    break;
                }
                else   //问题就出在这一句上
                {
                    if(Get(L)=='{')
                    {
                        Pop(&L);
                    }
                    else
                    {
                        flag=0;
                        break;
                    }
                }
            }
            else if(s[i]==']')
            {

                if(Empty(L))
                {
                    flag=0;
                    break;
                }
                else
                {
                    if(Get(L)=='[')
                    {
                        Pop(&L);
                    }
                    else
                    {
                        flag=0;
                        break;
                    }
                }
            }
        }
        if(!Empty(L))                                   //遍历完算术表达式之后,判断栈是否为空,如果不为空,标记flag=0;
        {
            flag=0;
        }
        if(flag==1&&Empty(L))                  //只有flag=1并且栈是空的,我们才能说我们输入的括号是完全匹配的
        {
            printf("yes\n");
        }
        else                       
        {
            printf("no\n");
        }
    }
    return 0;
}

(八)、运行结果

 四、完整代码


#include <stdio.h>
#include <stdlib.h>
#define Maxsize 100
typedef struct ST
{
    char data[Maxsize];
    int  top;
}Stack;
void Init(Stack *L)
{
    L->top=-1;
}
void Push(Stack *L,char x)
{
    if(L->top>=Maxsize)
    {
        return;
    }
    L->top++;
    L->data[L->top]=x;
}
int Empty(Stack L)
{
    if(L.top==-1)
    {
        return 1;//为空返回1
    }
    return 0;    //不为空返回0
}
void Print(Stack L)
{
    for(int i=L.top;i>-1;i--)
    {
        printf("%c   ",L.data[i]);
    }
}
void Pop(Stack *L)
{
    if(L->top==-1)
    {
        return;
    }
    L->top--;
}
char Get(Stack L)
{
    return L.data[L.top];
}
int main()
{
    Stack L;
    char s[100];
    while(gets(s))
    {
        Init(&L);
        int flag=1;
        //printf("%s",s);
        for(int i=0;s[i]!='\0';i++)
        {
            if(s[i]=='('||s[i]=='['||s[i]=='{')
            {
                if(L.top<Maxsize)
                {
                    char x=s[i];
                    Push(&L,x);
                }

            }
            else if(s[i]==')')
            {

                if(Empty(L))
                {
                    flag=0;
                    break;
                }
                else  
                {
                    if(Get(L)=='(')
                    {
                        Pop(&L);
                    }
                    else
                    {
                        flag=0;
                        break;
                    }
                }
            }
            else if(s[i]=='}')
            {

                if(Empty(L))
                {
                    flag=0;
                    break;
                }
                else   
                {
                    if(Get(L)=='{')
                    {
                        Pop(&L);
                    }
                    else
                    {
                        flag=0;
                        break;
                    }
                }
            }
            else if(s[i]==']')
            {
                if(Empty(L))
                {
                    flag=0;
                    break;
                }
                else   
                {
                    if(Get(L)=='[')
                    {
                        Pop(&L);
                    }
                    else
                    {
                        flag=0;
                        break;
                    }
                }
            }
        }
        if(!Empty(L))
        {
            flag=0;
        }
        if(flag==1&&Empty(L))
        {
            printf("yes\n");
        }
        else
        {
            printf("no\n");
        }
    }
    return 0;
}

总结:括号匹配问题比较经典,它完美的考察了我们对栈的理解,熟悉栈的操作是基本的,只有把它结合到具体的问题上加以运用才是真的掌握。理论联系实际,实践是检验真理的唯一标准。继续加油。

有关数据结构练习题之栈与队列:括号匹配问题(C语言实现)的更多相关文章

  1. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby 正则表达式 - 如何替换字符串中匹配项的第 n 个实例 - 2

    在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg

  4. ruby - 匹配未转义的平衡定界符对 - 2

    如何匹配未被反斜杠转义的平衡定界符对(其本身未被反斜杠转义)(无需考虑嵌套)?例如对于反引号,我试过了,但是转义的反引号没有像转义那样工作。regex=/(?!$1:"how\\"#expected"how\\`are"上面的正则表达式不考虑由反斜杠转义并位于反引号前面的反斜杠,但我愿意考虑。StackOverflow如何做到这一点?这样做的目的并不复杂。我有文档文本,其中包括内联代码的反引号,就像StackOverflow一样,我想在HTML文件中显示它,内联代码用一些spanMaterial装饰。不会有嵌套,但转义反引号或转义反斜杠可能出现在任何地方。

  5. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  6. ruby - 匹配大写字母并用后续字母填充,直到一定的字符串长度 - 2

    我有一个驼峰式字符串,例如:JustAString。我想按照以下规则形成长度为4的字符串:抓取所有大写字母;如果超过4个大写字母,只保留前4个;如果少于4个大写字母,则将最后大写字母后的字母大写并添加字母,直到长度变为4。以下是可能发生的3种情况:ThisIsMyString将产生TIMS(大写字母);ThisIsOneVeryLongString将产生TIOV(前4个大写字母);MyString将生成MSTR(大写字母+tr大写)。我设法用这个片段解决了前两种情况:str.scan(/[A-Z]/).first(4).join但是,我不太确定如何最好地修改上面的代码片段以处理最后一种

  7. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  8. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  9. ruby-on-rails - Rails 3,嵌套资源,没有路由匹配 [PUT] - 2

    我真的为这个而疯狂。我一直在搜索答案并尝试我找到的所有内容,包括相关问题和stackoverflow上的答案,但仍然无法正常工作。我正在使用嵌套资源,但无法使表单正常工作。我总是遇到错误,例如没有路线匹配[PUT]"/galleries/1/photos"表格在这里:/galleries/1/photos/1/edit路线.rbresources:galleriesdoresources:photosendresources:galleriesresources:photos照片Controller.rbdefnew@gallery=Gallery.find(params[:galle

  10. ruby - 我如何添加二进制数据来遏制 POST - 2

    我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_

随机推荐