【数据结构】符号配对

8 阅读4分钟

题目链接

习题3.8 符号配对 - 浙大版《数据结构(第2版)》题目集

整体思路

  1. 循环读取字符,将字符存储到字符数组,直到
    1. 读到EOF
    2. 读到连续的\n . \n
    3. 超过字符数组最大限制
  2. 遍历字符串
    1. 如果读到左符号,入栈;
    2. 读到右符号,出栈
      1. 若栈空,说明缺少左符号,此时退出循环
      2. 若栈不空,将出栈的左符号与读到的右符号对比,若相等则匹配。若不相等,认为缺少右符号,退出循环
  3. 遍历结束,根据当前状态判断输出
    1. 栈不空,认为缺少右符号
    2. 栈空,若此前因为缺少左符号退出循环,认为缺少左符号。否则认为匹配正确,输出YES

注意事项

  1. 左注释符号/*和右注释符号*/由两个符号组成,此时应单独判断,并应考虑一些重合情况(类似/*/ 等不能认为匹配成功)
  2. 题目未说明左注释符号/*和右注释符号*/之间的注释是否需要匹配,实际测试注释中出现的符号也需要匹配
  3. 存储输入是字符数组,所以/*入栈简化为将/+*入栈(实际为字符Y

代码

#include <stdio.h>
#include <stdbool.h>
#include <string.h>

#define MAX_SIZE 1000

bool Push(char* stack, int* top, char c);
bool Pop(char* stack, int* top, char *c);
bool isLeftChar(char ch);
bool isRightChar(char ch);
bool isLeftCommentChar(char ch, char nextCh);
bool isRightCommentChar(char ch, char nextCh);
bool isMatch(char leftCh, char rightCh);

int main()
{
    char ch;
    char buff[MAX_SIZE] = {'\0'};
    int top = 0;
    int num = 0;
    char stack[MAX_SIZE] = {'\0'};
    bool ret = false;
    char rightErrCh = 0;
    bool rightErr = false;
    char leftErrCh = 0;
    bool leftErr = false;

    // 读取输入,直到读到EOF或者读到连续的\n.\n或超过字符数组的最大限制
    while ((buff[num] = getchar()) != EOF && num < MAX_SIZE)
    {
        if (num >= 2 && (buff[num] == '\n' && buff[num-1] == '.' && buff[num-2] == '\n'))
        {
            break;
        }
        num++;
    }

    // 处理输入的字符
    for (int i = 0; i < num; i++)
    {
        // 是左符号
        if (isLeftChar(buff[i]))
        {
            // 入栈
            ret = Push(stack, &top, buff[i]);
            if (ret == false)
            {
                // 栈满
            }
        }
        // 是右符号
        else if (isRightChar(buff[i]))
        {
            // 出栈
            ret = Pop(stack, &top, &ch);
            if (ret == false)
            {
                // 栈空,认为缺少左符号
                rightErr = true;
                rightErrCh = buff[i];
                // 退出循环
                break;
            }
            else if (!isMatch(ch, buff[i]))
            {
                // 符号不匹配,认为缺少右符号
                leftErr = true;
                leftErrCh = ch;
                // 退出循环
                break;
            }
        }
        // 是左注释符号
        if (isLeftCommentChar(buff[i], buff[i+1]))
        {
            // 入栈
            ret = Push(stack, &top, '/' + '*');
            if (ret == false)
            {
                // 栈满
            }
            else
            {
                // 跳过左注释符号的*
                i++;
            }
        }
        // 是右注释符号
        else if (isRightCommentChar(buff[i], buff[i+1]))
        {
            // 出栈
            ret = Pop(stack, &top, &ch);
            if (ret == false)
            {
                // 栈空,认为缺少左注释符号
                rightErr = true;
                rightErrCh = '*' + '/';
                // 退出循环
                break;
            }
            else if (!isMatch(ch, '*' + '/'))
            {
                // 注释符号不匹配,认为缺少右注释符号
                leftErr = true;
                leftErrCh = ch;
                // 退出循环
                break;
            }
            else
            {
                // 跳过右注释符号的/
                i++;
            }
        }
    }

    // 输出结果
    
    // 栈不空
    if (top > 0)
    {
        // 由于缺少右符号退出循环
        if (leftErr == true)
        {
            if (leftErrCh == '/' + '*')
            {
                printf("NO\n/*-?");
            }
            else
            {
                printf("NO\n%c-?", leftErrCh);
            }
        }
        // 遍历结束时栈不空,认为缺少右符号
        else
        {
            // 取栈顶元素
            leftErrCh = stack[top-1];
            if (leftErrCh == '/' + '*')
            {
                printf("NO\n/*-?");
            }
            else
            {
                printf("NO\n%c-?", leftErrCh);
            }   
        }

    }
    // 栈空
    else
    {
        // 没有错误
        if (rightErr == false && leftErr == false)
        {
            printf("YES");
        }
        // 有错误
        else
        {
            // 由于缺少左符号退出循环
            if (rightErr)
            {
                if (rightErrCh == '*' + '/')
                {
                    printf("NO\n?-*/");
                }
                else
                {
                    printf("NO\n?-%c", rightErrCh);
                }                
            }
        }
    }

    return 0;
}

/**
 * @brief 入栈
 * 
 * @param stack 栈
 * @param top 栈顶索引
 * @param c 入栈字符
 * @return true 成功入栈
 * @return false 栈满,入栈失败
 */
bool Push(char* stack, int* top, char c)
{
    bool ret = false;

    if (*top >= MAX_SIZE)
    {
        // 栈满
        ret = false;
    }
    else
    {
        stack[(*top)++] = c;
        ret = true;
    }

    return ret;
}

/**
 * @brief 出栈
 * 
 * @param stack 栈
 * @param top 栈顶索引
 * @param ch 出栈字符
 * @return true 成功出栈
 * @return false 栈空,出栈失败
 */
bool Pop(char* stack, int* top, char *c)
{
    bool ret = false;

    if (*top <= 0)
    {
        ret = false;
    }
    else
    {
        *c = stack[--(*top)];
        ret = true;
    }

    return ret;
}

/**
 * @brief 判断是否为左符号
 * 
 * @param ch 字符
 * @return true 是左符号
 * @return false 不是左符号
 */
bool isLeftChar(char ch)
{
    return ch == '(' || ch == '{' || ch == '[';
}

/**
 * @brief 判断是否为右符号
 * 
 * @param ch 字符
 * @return true 是右符号
 * @return false 不是右符号
 */
bool isRightChar(char ch)
{
    return ch == ')' || ch == '}' || ch == ']';
}

/**
 * @brief 判断是否为左注释符号
 * 
 * @param ch 字符
 * @param nextCh 下一个字符
 * @return true 是左注释符号
 * @return false 不是左注释符号
 */
bool isLeftCommentChar(char ch, char nextCh)
{
    return ch == '/' && nextCh == '*';
}

/**
 * @brief 判断是否为右注释符号
 * 
 * @param ch 字符
 * @param nextCh 下一个字符
 * @return true 是右注释符号
 * @return false 不是右注释符号
 */
bool isRightCommentChar(char ch, char nextCh)
{
    return ch == '*' && nextCh == '/';
}

/**
 * @brief 判断左右符号是否匹配
 * 
 * @param leftCh 左符号
 * @param rightCh 右符号
 * @return true 匹配
 * @return false 不匹配
 */
bool isMatch(char leftCh, char rightCh)
{
    bool ret = false;

    if (leftCh == '(' && rightCh == ')')
    {
        ret = true;
    }
    else if (leftCh == '{' && rightCh == '}')
    {
        ret = true;
    }
    else if (leftCh == '[' && rightCh == ']')
    {
        ret = true;
    }
    else if (leftCh == '/' + '*' && rightCh == '*' + '/')
    {
        ret = true;
    }

    return ret;
}