数据结构期末复习·括号匹配

最近好像开始炒冷饭了0.0(因为自己太菜了洛谷写不明白

一·题面

【问题描述】

编写一程序检查C源程序文件中{}、()等括号是否匹配,并输出第一个检测到的不匹配的括号及所对应括号所在的行号(程序中只有一个括号不匹配)。

注意:

1.除了括号可能不匹配外,输入的C源程序无其它语法错误。

2.字符常量、字符串常量及注释中括号不应被处理,注释包括单行注释//多行/* */注释

3.字符常量和字符串常量中不包含转义字符\'和\"

4.程序中出现有意义括号的个数不超过200个;

不匹配判断规则:

1.当检测的程序括号为'{'时,若其前序尚未匹配的括号为'('时,输出该'('左括号及所在行号; 

2.当遇到一个不匹配的右括号')'或'}'时,输出该右括号及所在行号;

3.当程序处理完毕时,还存在不匹配的左括号时,输出该左括号及所在行号。

【输入形式】

打开当前目录下文件example.c,查询其括号是否匹配。该文件中每行字符数不超过200

【输出形式】

若存在括号不匹配时,应输出首先能判断出现不匹配的括号及其所在的行号。当出现括号不匹配时,按下面要求输出相关信息:

without maching at line

其中为‘{’, ‘}’, ‘(’, ‘)’等符号,为该符号所在的行号。

若整个程序括号匹配,则按下面所示顺序输出括号匹配情况,中间没有空格。

(){(()){}}

【样例输入1】

若当前目录下输入文件example.c中内容如下:

#include

int main(){

printf("{ hello world }\n"); // }

)

【样例输出1】

without maching ')' at line 4

【样例输入2】

若当前目录下输入文件example.c中内容如下:

#include

int main(){

printf("{ hello world }d\n"); /* }*/

【样例输出2】

without maching '{' at line 2

【样例输入3】

若当前目录下输入文件example.c中内容如下:

#include

int main(){

printf("{ hello world }d\n"); /* }*/

}

【样例输出3】

(){()}


【样例说明】

样例1:在注释部分和字符串中的括号不考虑,在将程序处理之后得到的括号序列是(){()),遇到右括号时与最近的左括号匹配,发现最后一个小括号和大括号不匹配。

样例2:处理之后的括号序列是(){(),在最后缺少了右大括号,那么应该输出与之相对应的左括号不匹配。

【评分标准】

通过所有测试点得满分。

题意分析:

括号匹配本身是个很简单的问题,使用栈就可以解决,但是这个题目的难点不在于此:

本题把括号匹配这个经典的栈问题放到了一个代码的情景之中,出现了单行注释,多行注释,引号等多种干扰,本题的难点就在于排除这些干扰项

二·干扰处理

由题,文章有四种干扰:

单行注释// 多行注释/*...*/ 单引号'c' 双引号"..."

我们可以发现,除了多行注释都发生在一行之中,所以采取的策略是:先读入一行,处理完三种情况以后,存入到一个二维数组中,最后再处理多行注释。

1·单行处理

对于单行的处理,第一次接触这个题的时候我想到的是strstr函数,但是这样有一个弊端:三种干扰可能交杂出现,而其优先级应该是和其出现位置有关的(也就是说我们要优先考虑最先出现的干扰项),而用strstr函数的时候,优先级和你调用三个strstr函数的顺序有关。这样说可能亿点点抽象,不如看一个例子:

对于"xx//x",这个//实在双引号内部的,不应该被识别到,但是如果strstr(line,"//")在strstr(line,"\"")之前调用,就会错误识别到这个//

所以从左到右遍历字符串,同时检查有没有出现三种更舒服:

void process_line(char *line){
    for(int i=0;i<strlen(line)-1;i++){
        if(line[i]=='/'&&line[i+1]=='/'){
            for(;i<strlen(line);i++) line[i]='0';
            break;
        }
        else if(line[i]=='\''&&line[i+2]=='\''){
            line[i]=line[i+1]=line[i+2]='0';
            i=i+2;
            continue;
        }
        else if(line[i]=='\"'){
            line[i++]='0';
            while(line[i]!='\"') line[i++]='0';
            line[i]='0';
            continue;
        }
    }
}

2·多行处理

多行处理就没什么技巧性了,用一个flag记录一下即可

void process_all(){
    int flag = 0;
    for(int i=0;i<lcnt;i++){
        if(flag){
            char *q = strstr(art[i],"*/");
            if(q!=NULL){
                flag = 0;
                for(char *p=art[i];p<=q+1;p++) *p='0';
            }
        }

         char *p=strstr(art[i],"/*");
         if(p!=NULL){
             char *q = strstr(art[i],"*/");
             if(q!=NULL){
                 for(;p<=q+1;p++) *p='0';
             }
             else{
                 for(;*p!='\0';p++) *p='0';
                 flag = 1;
             }
         }
    }
}

三·括号匹配

括号匹配对四种括号分别讨论即可,注意,由于要输出错误括号的行数,所以要用一个结构体在记录括号的同时也记录行数。(同时,对于行数,在读入的时候也要小心。样例两行之间是有一个空行的,要跳过空行,否则会导致行数比预期的大)

void brackets_match(){
    brk stack[100];
    int top = -1;
    for(int i=0;i<lcnt;i++){
        for(int j=0;j<strlen(art[i]);j++){
            if(art[i][j]=='{'){
                if(top>=0&&stack[top].c=='('){
                    printf("without maching '(' at line %d",stack[top].lnum);
                    return ;
                }
                top++;
                stack[top].c='{';
                stack[top].lnum=i+1;
            }
            if(art[i][j]==')'){
                if(top>=0&&stack[top].c=='(') top--;
                else{
                    printf("without maching ')' at line %d",i+1);
                    return ;
                }
            }
            if(art[i][j]=='}'){
                if(top>=0&&stack[top].c=='{') top--;
                else{
                    printf("without maching '}' at line %d",i+1);
                    return ;
                }
            }
            if(art[i][j]=='('){
                top++;
                stack[top].c='(';
                stack[top].lnum=i+1;
            }
        }
    }
    if(top>=0&&(stack[top].c=='{'||stack[top].c=='(')){
        printf("without maching '%c' at line %d",stack[top].c,stack[top].lnum);
        return ;
    }
    puts("well brackets");
}

全部代码如下:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXLINE 210
#define MAXSIZE 1000
/*
先对一行进行处理 存储全部以后再对多行注释处理
*/
char art[MAXSIZE][MAXLINE]={{'\0'}};
int lcnt=0;

void process_line(char *line){
    for(int i=0;i<strlen(line)-1;i++){
        if(line[i]=='/'&&line[i+1]=='/'){
            for(;i<strlen(line);i++) line[i]='0';
            break;
        }
        else if(line[i]=='\''&&line[i+2]=='\''){
            line[i]=line[i+1]=line[i+2]='0';
            i=i+2;
            continue;
        }
        else if(line[i]=='\"'){
            line[i++]='0';
            while(line[i]!='\"') line[i++]='0';
            line[i]='0';
            continue;
        }
    }
}

void process_all(){
    int flag = 0;
    for(int i=0;i<lcnt;i++){
        if(flag){
            char *q = strstr(art[i],"*/");
            if(q!=NULL){
                flag = 0;
                for(char *p=art[i];p<=q+1;p++) *p='0';
            }
        }

         char *p=strstr(art[i],"/*");
         if(p!=NULL){
             char *q = strstr(art[i],"*/");
             if(q!=NULL){
                 for(;p<=q+1;p++) *p='0';
             }
             else{
                 for(;*p!='\0';p++) *p='0';
                 flag = 1;
             }
         }
    }
}

typedef struct braket_type{
    char c;
    int lnum;
}brk;

void brackets_match(){
    brk stack[100];
    int top = -1;
    for(int i=0;i<lcnt;i++){
        for(int j=0;j<strlen(art[i]);j++){
            if(art[i][j]=='{'){
                if(top>=0&&stack[top].c=='('){
                    printf("without maching '(' at line %d",stack[top].lnum);
                    return ;
                }
                top++;
                stack[top].c='{';
                stack[top].lnum=i+1;
            }
            if(art[i][j]==')'){
                if(top>=0&&stack[top].c=='(') top--;
                else{
                    printf("without maching ')' at line %d",i+1);
                    return ;
                }
            }
            if(art[i][j]=='}'){
                if(top>=0&&stack[top].c=='{') top--;
                else{
                    printf("without maching '}' at line %d",i+1);
                    return ;
                }
            }
            if(art[i][j]=='('){
                top++;
                stack[top].c='(';
                stack[top].lnum=i+1;
            }
        }
    }
    if(top>=0&&(stack[top].c=='{'||stack[top].c=='(')){
        printf("without maching '%c' at line %d",stack[top].c,stack[top].lnum);
        return ;
    }
    puts("well brackets");
}


int main(){
    char line[MAXLINE];
    FILE *src = fopen("example.c","r");
    while(fgets(line,210,src)){
        if(line[0]=='\n') continue;//跳过空行
        process_line(line);
        //puts(line);
        strcpy(art[lcnt++],line);
    }
    process_all();
    //for(int i=0;i<lcnt;i++) printf("%d  ",i+1),puts(art[i]);

    brackets_match();
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值