PTA 7-4 符号配对

请编写程序检查C语言源程序中下列符号是否配对:/**/()[]{}

输入格式:

输入为一个C语言源程序。当读到某一行中只有一个句点.和一个回车的时候,标志着输入结束。程序中需要检查配对的符号不超过100个。

输出格式:

首先,如果所有符号配对正确,则在第一行中输出YES,否则输出NO。然后在第二行中指出第一个不配对的符号:如果缺少左符号,则输出?-右符号;如果缺少右符号,则输出左符号-?

输入样例1:

void test()
{
    int i, A[10];
    for (i=0; i<10; i++) { /*/
        A[i] = i;
}
.

输出样例1:

NO
/*-?

输入样例2:

void test()
{
    int i, A[10];
    for (i=0; i<10; i++) /**/
        A[i] = i;
}]
.

输出样例2:

NO
?-]

输入样例3:

void test()
{
    int i
    double A[10];
    for (i=0; i<10; i++) /**/
        A[i] = 0.1*i;
}
.

输出样例3:

YES

 代码+总结:

        换种方式来写吧

        首先这种括号配对问题肯定先想到栈。这里为了方便,我把 ([{ /* 统称为左括号,另一边统称为右括号。

        输入的是一个以 单行. 为结尾的c语言代码,而我们要的只是符号,所以能想到我们先用循环把代码逐部分读入,当读到以 . 为首元素的部分时退出循环。

        再这个大循环内我们还要对读入的部分再做循环,来找到我们需要的括号类字符处理。其中比较特殊的时 /* */ 两个,我们再读取的时候对这两个字符做特殊处理,用 值 1,2分别代表这两个字符,再把读取到的有效字符进行处理,这里我把读取到的字符用函数judge()处理:

char str[1000]; scanf("%s", str);  // 先输入下字符数组
    while (str[0] != '.')
    {
        for (int i = 0; str[i]; i++)
        {
            // 下面一堆if其实就是查找是不是括号啥的
            if (str[i] == '/' && str[i+1] == '*')  {i ++;  flag = judge(1);}
            else if (str[i] == '*' && str[i+1] == '/')  {i ++; flag = judge(2);}
            else if (str[i] == '(' || str[i] == ')') flag = judge(str[i]);
            else if (str[i] == '[' || str[i] == ']') flag = judge(str[i]);
            else if (str[i] == '{' || str[i] == '}') flag = judge(str[i]);
            if (flag) return 0;  // 如果上面的judge返回1就直接return
        }
        memset(str, 0, sizeof(str));  // 重置一下暂存的字符数组
        scanf("%s", str);  // 输入新的字符数组
    }

       

        可以看到我还用flag来接收了judge()的返回值,先留着不说,我们来分析judge()要干的活都有啥。

        judge()负责处理输入的括号字符,可以说是这段代码的核心函数。那么怎么样才算是不能匹配呢?

接下来介绍一下分辨条件:

        如果栈是空的,且读入的是右括号--不匹配,直接输出NO+七七八八的

        如果栈非空:

                读取到左括号,直接入栈

                读取到右括号:

                        1.如果与栈顶匹配,栈顶退栈。

                        2.如果不匹配--不匹配,直接输出NO+七七八八的。

        最后读取代码结束后,如果栈内非空,说明有左括号没得匹配,直接输出NO+七七八八的。

        知道了条件,写judge()就轻松多了,但是想要输出 NO+七七八八的 之后就让程序停止运行,就得有个东西通知主函数我已经输出过 NO+七七八八的 的了,这就是用flag来接收judge()返回值的作用。

int judge(char ch)
{
    // 如果栈还是空的
    if (top == 0 )
    {
        to_str(ch);
        // 如果读取到的是右侧字符,那么肯定不匹配,直接输出no
        if (ch == 2 || ch == ')' || ch == ']' || ch == '}') {printf("NO\n?-%s", note); return 1;}
        stack[top++] = ch;
    }
    else  // 栈非空
    {
        to_str(stack[top - 1]);
        if (ch == 1 || ch == '(' || ch == '[' || ch == '{') stack[top++] = ch;  // 左括号直接入栈
        else  // 右括号判断
        {
            if (ch - stack[top-1] == 1 || ch - stack[top-1] == 2) top--; // 能配对的话退栈
            else {printf("NO\n%s-?", note); return 1;}  // 不能配对的话结束
        }
    }
    return 0;
}

        可以看到我在这里面又弄了个 to_str(),由于之前图方便把 /* */ 作了特殊处理,因此在输出的时候就要把 1、2 翻译成 /* 、*/。

void to_str(char ch)
{
    memset(note, 0, sizeof(note));
    if (ch == 1)   {note[0] = '/';  note[1] = '*';}
    else if (ch == 2) {note[0] = '*';  note[1] = '/';}
    else note[0] = ch;
}

       

        到这代码就差不多结束了,再在主函数循环后添加一个判断栈是否非空的语句就ok了,不过需要注意一下,如果非空的话我们要输出栈底的元素(题目要求第一个不匹配的)

// 结束循环后如果栈内还有东西的话,那么括号肯定不匹配
    if (top != 0)
    {
        to_str(stack[0]);  // stack[0] 栈底
        printf("NO\n%s-?", note);
        return 0;
    }
    printf("YES");

        

        接下来给出完整代码

#include<stdio.h>
#include<string.h>
char stack[200], note[3];
int top = 0;
void to_str(char ch)  // 因为把 /* */ 当作一个字符处理了,所以在这里要还原一下
{
    memset(note, 0, sizeof(note));
    if (ch == 1)   {note[0] = '/';  note[1] = '*';}
    else if (ch == 2) {note[0] = '*';  note[1] = '/';}
    else note[0] = ch;
}

int judge(char ch)
{
    // 如果栈还是空的
    if (top == 0 )
    {
        to_str(ch);
        // 如果读取到的是右侧字符,那么肯定不匹配,直接输出no
        if (ch == 2 || ch == ')' || ch == ']' || ch == '}') {printf("NO\n?-%s", note); return 1;}
        stack[top++] = ch;
    }
    else  // 栈非空
    {
        to_str(stack[top - 1]);
        if (ch == 1 || ch == '(' || ch == '[' || ch == '{') stack[top++] = ch;  // 左括号直接入栈
        else  // 右括号判断
        {
            if (ch - stack[top-1] == 1 || ch - stack[top-1] == 2) top--; // 能配对的话退栈
            else {printf("NO\n%s-?", note); return 1;}  // 不能配对的话结束
        }
    }
    return 0;
}

int main()
{
    int flag = 0;
    char str[1000]; scanf("%s", str);  // 先输入下字符数组
    while (str[0] != '.')
    {
        for (int i = 0; str[i]; i++)
        {
            // 下面一堆if其实就是查找是不是括号啥的
            if (str[i] == '/' && str[i+1] == '*')  {i ++;  flag = judge(1);}
            else if (str[i] == '*' && str[i+1] == '/')  {i ++; flag = judge(2);}
            else if (str[i] == '(' || str[i] == ')') flag = judge(str[i]);
            else if (str[i] == '[' || str[i] == ']') flag = judge(str[i]);
            else if (str[i] == '{' || str[i] == '}') flag = judge(str[i]);
            if (flag) return 0;  // 如果上面的judge返回1就直接return
        }
        memset(str, 0, sizeof(str));  // 重置一下暂存的字符数组
        scanf("%s", str);  // 输入新的字符数组
    }
    // 结束循环后如果栈内还有东西的话,那么括号肯定不匹配
    if (top != 0)
    {
        to_str(stack[0]);
        printf("NO\n%s-?", note);
        return 0;
    }
    printf("YES");
    return 0;
}

<think>好的,用户想了解符号配对栈的实现方法。首先,我需要回忆符号配对的基本原理。符号配对通常使用栈这种数据结构,因为后进先出的特性很适合检查嵌套结构。比如括号、方括号、大括号的匹配,遇到左符号入栈,遇到右符号时检查栈顶是否对应的左符号。如果匹配则出栈,否则报错。 接下来,用户提到的引用内容里提到了几个关键点:引用1说明了符号类型和匹配规则,引用2展示了入栈操作的代码片段,引用3提到了输入的结束条件和符号数量的限制。这些信息需要整合到回答中。 然后,我需要确定具体的实现步骤。首先是初始化栈,然后遍历输入的每个字符。遇到左符号就入栈,遇到右符号则检查栈是否为空或者栈顶是否匹配。如果不匹配,直接返回错误。遍历结束后,如果栈不为空,说明有未闭合的左符号,也报错。 还要注意代码实现部分,用户可能需要一个具体的例子。例如,用数组实现栈结构,包括push和pop操作。引用2中的push函数可能是一个例子,但需要调整变量名和结构,使其更清晰易懂。 另外,边界条件需要考虑,比如空输入、只有右符号、或者符号数量超过限制的情况。根据引用3,程序中需要检查的配对符号不超过100个,所以栈的大小可以设为100,或者动态调整。 用户可能对时间复杂度感兴趣,遍历一次输入,时间复杂度是O(n),空间复杂度也是O(n)最坏情况下。还需要考虑不同编程语言的实现差异,但用户提供的例子是C语言的,所以保持一致性。 最后,生成相关问题时要覆盖常见问题,如错误类型、优化方法、扩展应用等,帮助用户深入理解。</think>符号配对问题的栈实现方法可分为五个步骤,以下以C语言为例说明括号`()[]{}`的匹配检测流程: ### 一、栈结构定义 采用顺序栈存储结构,定义最大容量为100: ```c #define MAX_SIZE 100 typedef struct { char data[MAX_SIZE]; int top; } Stack; ``` ### 二、初始化与基本操作 初始化空栈并实现核心操作: ```c void init(Stack *s) { s->top = -1; } int push(Stack *s, char x) { if (s->top >= MAX_SIZE-1) return 0; // 栈满 s->data[++s->top] = x; return 1; } char pop(Stack *s) { if (s->top < 0) return '\0'; // 栈空 return s->data[s->top--]; } ``` ### 三、符号匹配算法 遍历输入字符时的处理逻辑: 1. **左符号处理** ```c if (ch == '(' || ch == '[' || ch == '{') { push(&stack, ch); } ``` 2. **右符号校验** ```c else if (ch == ')' || ch == ']' || ch == '}') { char match = pop(&stack); if ((ch == ')' && match != '(') || (ch == ']' && match != '[') || (ch == '}' && match != '{')) { printf("Mismatch: %c vs %c\n", match, ch); return 0; } } ``` ### 四、最终状态检查 输入结束后验证栈是否清空: ```c if (stack.top != -1) { printf("Unclosed symbol: %c\n", stack.data[stack.top]); return 0; } ``` ### 五、时间复杂度分析 该算法时间复杂度为$O(n)$,空间复杂度$O(n)$,满足PTA题目中符号数量不超过100的要求[^3]。测试案例需覆盖以下场景: - 完全匹配:`{[()]}` - 交叉错误:`([)]` - 单边多余:`(()`
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值