习题3.8 符号配对 (20 分)

请编写程序检查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

括号的匹配,当然首先想起和堆栈有关,题目不难,但是考验写代码的能力。放出我的撇脚代码:

#include <stdio.h>

/* K & R Stack */
#define MAXVAL 100
static int val[MAXVAL];
static int sp = 0;

void push(int ch)
{
    if (sp < MAXVAL) {
        val[sp++] = ch;
    } else {
        // stack full
    }
}

int pop(void)
{
    if (sp > 0) {
        return val[--sp];
    } else {
        return -1;
    }
}

int isEmpty(void) { return sp == 0; }

int isLeftSymbol(int ch);
int getMatcher(int ch);
const char* getOriginalSymbol(int ch);

int main()
{
    char symbols[100];
    char line[1000];
    char result[100] = "YES\n";
    int i, index, ch;
    index = 0;

    // 读所有的要配对的符号
    while (fgets(line, sizeof(line)/sizeof(line[0]), stdin) != NULL) {
        if (line[0] == '.' && line[1] == '\n') {
            break;
        }
        for (i = 0; line[i] != '\0'; i++) {
            ch = line[i];
            if (line[i] == '/' && line[i+1] == '*') {
                symbols[index++] = '<';
                i++;
            } else if (line[i] == '*' && line[i+1] == '/') {
                symbols[index++] = '>';
                i++;
            } else if (ch == '(' || ch == ')' ||
                       ch == '[' || ch == ']' ||
                       ch == '{' || ch == '}')
            {
                symbols[index++] = ch;
            }
        }
    }
    symbols[index] = '\0';
    
    // printf("%s\n", symbols);    /* 输出所有读到的符号 */

    /* 检查符号匹配 */
    for (i = 0; i < index; i++) {
        int ch = symbols[i];
        if (isLeftSymbol(ch)) { /* 是左边的符号,push 到堆栈里面去 */
            push(symbols[i]);
        } else {    /* 是右边的符号 */
            int leftSymbol = pop(); /* 从堆栈取出要匹配的左边的符号 */
            if (leftSymbol != -1) { /* 还有左边的符号 */
                int rightSymbol = getMatcher(leftSymbol);
                if (rightSymbol != ch) {    /* 左边符号想要的右符号是不是现在遇到的右边的符号(ch) */
                    sprintf(result, "NO\n%s-?\n", getOriginalSymbol(leftSymbol));
                    break;
                }
            } else {    /* 当前遇到的符号没有左符号来匹配 */
                sprintf(result, "NO\n?-%s\n", getOriginalSymbol(ch));
                break;
            }
        }
    }

    if (i == index && !isEmpty()) {    /* 匹配完所有的括号后,如果堆栈不为空有多余的左括号/符号 */
        sprintf(result, "NO\n%s-?\n", getOriginalSymbol(pop()));
    }

    printf("%s", result);
    return 0;
}


int isLeftSymbol(int ch)
{
    return ch == '<' || ch == '(' || ch == '[' || ch == '{';
}

int getMatcher(int ch)
{
    static int map[128] = {
        ['<'] = '>', 
        ['>'] = '<',
        ['('] = ')',
        [')'] = '(',
        ['['] = ']',
        [']'] = '[',
        ['{'] = '}',
        ['}'] = '{'
    };

    return ch >= 0 && ch < 128 ? map[ch] : 0;
}

const char* getOriginalSymbol(int ch)
{
    static const char *symbols[128] = {
        ['<'] = "/*",
        ['>'] = "*/",
        ['('] = "(",
        [')'] = ")",
        ['['] = "[",
        [']'] = "]",
        ['{'] = "{",
        ['}'] = "}",
    };

    return ch >= 0 && ch < 128 ? symbols[ch] : "";
}

posted @ 2021-03-27 11:36  wngtk  阅读(695)  评论(0编辑  收藏  举报