栈练习之Example005-检查一个程序中的花括号方括号和圆括号是否配对

Posted 二木成林

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了栈练习之Example005-检查一个程序中的花括号方括号和圆括号是否配对相关的知识,希望对你有一定的参考价值。

Example005

题目

试编写一个算法,检查一个程序中的花括号、方括号和圆括号是否配对,若全部配对,则返回1,否则返回0。对于程序中出现的一对单引号或双引号内的字符不进行括号配对检查。39为单引号的ASCII 值,34为双引号的ASCII值,单引号和双引号如果出现则必成对出现。

分析

在算法中,扫描程序中的每一个字符,当扫描到每个左花括号(即 )、左方括号(即 [)、左圆括号(即 ()字符时,令其进栈;当扫描到右花括号(即 )、右方括号(即 ])、右圆括号(即 ))时,则检查栈顶是否为相应的左括号,若是则做退栈处理,若不是则表明出现了语法错误,返回0。当扫描到程序文件结尾后,若栈为空,则表明没有发现括号配对错误,返回1;否则表明栈中还有未配对的括号,返回0。另外,对于一对单引号或双引号内的字符不进行括号配对检查。

这个题之前也做过一次,可参考:考研数据结构之栈(2.5)——练习题之编写一个算法,检查一个程序中的花括号、方括号和圆括号是否配对(C表示)

图解

a[c'ab[]',[(3[sdfe])345]aa]'' 为例,执行步骤如下所示:

  • (1)扫描到的字符是 a,不是括号字符,也非引号字符,所以继续判断下一个字符。
  • (2)扫描到的字符是 [,是左方括号,所以将其入栈。继续判断下一个字符。此时栈如下图所示:

  • (3)此时扫描到的字符是 c,不是括号字符,也非引号字符,所以继续判断下一个字符。
  • (4)扫描到的字符是 ',是单引号字符。因为题目中明确表示引号是成对出现的,所以跳过这对单引号及单引号之内的内容。所以跳过 'ab[]' 所有字符,即使引号之内有括号字符,也要跳过。
  • (5)此时扫描到的字符是 ,,不是括号字符,也非引号字符,所以继续判断下一个字符。
  • (6)此时扫描到的字符是 ,是左花括号字符,所以入栈。继续判断下一个字符。
  • (7)此时扫描到的字符是 [,是左方括号字符,所以入栈。继续判断下一个字符。
  • (8)此时扫描到的字符是 (,是左圆括号字符,所以入栈。继续判断下一个字符。此时栈如下图所示:

  • (9)此时扫描的字符是 3,不是括号字符,也非引号字符,所以继续判断下一个字符。
  • (10)此时扫描到的字符是 [,是左方括号字符,所以入栈。然后继续判断下一个字符。此时栈如下图所示:

  • (11)此时扫描到的字符是 s,不是括号字符,也非引号字符,所以继续判断下一个字符。
  • (12)此时扫描到的字符是 d,不是括号字符,也非引号字符,所以继续判断下一个字符。
  • (13)此时扫描到的字符是 f,不是括号字符,也非引号字符,所以继续判断下一个字符。
  • (14)此时扫描到的字符是 e,不是括号字符,也非引号字符,所以继续判断下一个字符。
  • (15)此时扫描到的字符是 ],将栈顶字符与当前扫描到的字符进行,正好栈顶字符是左方括号 [,与右方括号字符 ] 是一对,所以将栈顶元素出栈。然后继续判断下一个字符。此时栈如下图所示:

  • (16)此时扫描到的字符是 ),是右圆括号字符,将栈顶字符与当前扫描到的字符进行,正好栈顶字符是左圆括号 (,与右圆括号字符 ) 是一对,所以将栈顶元素出栈。然后继续判断下一个字符。此时栈如下图所示:

  • (17)此时扫描到的字符是 3,不是括号字符,也非引号字符,所以继续判断下一个字符。
  • (18)此时扫描到的字符是 4,不是括号字符,也非引号字符,所以继续判断下一个字符。
  • (19)此时扫描到的字符是 5,不是括号字符,也非引号字符,所以继续判断下一个字符。
  • (20)此时扫描到的字符是 ],将栈顶字符与当前扫描到的字符进行,正好栈顶字符是左方括号 [,与右方括号字符 ] 是一对,所以将栈顶元素出栈。然后继续判断下一个字符。此时栈如下图所示:

  • (21)此时扫描到的字符是 a,不是括号字符,也非引号字符,所以继续判断下一个字符。
  • (22)此时扫描到的字符是 a,不是括号字符,也非引号字符,所以继续判断下一个字符。
  • (23)此时扫描到的字符是 ,将栈顶字符与当前扫描到的字符进行,正好栈顶字符是左花方括号 ,与右花括号字符 是一对,所以将栈顶元素出栈。然后继续判断下一个字符。此时栈如下图所示:

  • (24)此时扫描到的字符是 ],将栈顶字符与当前扫描到的字符进行,正好栈顶字符是左方括号 [,与右方括号字符 ] 是一对,所以将栈顶元素出栈。然后继续判断下一个字符。此时栈如下图所示:

  • (25)扫描到的字符是 ',是单引号字符。因为题目中明确表示引号是成对出现的,所以跳过这对单引号及单引号之内的内容。所以跳过 '' 所有字符,包括引号字符本身也要跳过。
  • (26)扫描完成,判断如果栈空则表示序列中所有括号配对成功,则返回 1 表示成功。如果栈非空,则表示括号配对失败。

C实现

核心代码:

/**
 * 判断字符数组中的括号是否配对
 * @param arr 字符数组
 * @param n 数组长度
 * @return 如果所有括号配对成功则返回 1,否则返回 0 表示不匹配
 */
int isMatch(char arr[], int n) 
    // 声明栈并初始化,作为辅助解题数据结构使用
    SeqStack stack;
    init(&stack);

    // 变量,存放栈顶元素
    char top;

    // 变量,记录字符数组下标
    int i = 0;
    // 循环遍历包含括号的字符数组中的每个字符
    while (i < n) 
        // 为什么要用 ASCII 码值,因为不可能用一对单引号来引一个单引号字符,所以用数字来进行比较判断当前字符是否是单引号字符
        // 如果当前字符是单引号,则跳过一对单引号之后的所有字符,包括单引号本身
        if (arr[i] == 39) 
            // 跳过这对单引号中的第一个单引号
            i++;
            // 跳过单引号内的所有字符
            while (arr[i] != 39) 
                i++;
            
            // 跳过这对单引号中的最后一个单引号
            i++;
        
        // 如果当前字符是双引号,则跳过一对双引号之后的所有字符,包括双引号本身
        else if (arr[i] == 34) 
            // 跳过这对双引号中的第一个单引号
            i++;
            // 跳过双引号内的所有字符
            while (arr[i] != 34) 
                i++;
            
            // 跳过这对双引号中的最后一个双引号
            i++;
        
        // 如果是括号中的任何一个左括号
        else if (arr[i] == '(' || arr[i] == '[' || arr[i] == '') 
            // 将其存入栈中
            push(&stack, arr[i]);
            // 然后继续比较下一个字符
            i++;
        
        // 如果是右圆括号
        else if (arr[i] == ')') 
            // 获取栈顶元素
            getTop(stack, &top);
            // 如果栈顶元素是左圆括号,则正好配对 ()
            if (top == '(') 
                // 则将栈顶元素出栈
                pop(&stack, &top);
             else 
                // 如果不是则一定不配对,那么整个程序也配对失败,返回 0
                return 0;
            
            // 如果圆括号配对成功则继续比较下一个字符
            i++;
        
        // 如果是右方括号
        else if (arr[i] == ']') 
            // 获取栈顶元素
            getTop(stack, &top);
            // 如果栈顶元素是左方括号,则正好配对 []
            if (top == '[') 
                // 则将栈顶元素出栈
                pop(&stack, &top);
             else 
                // 如果不是则一定不配对,那么整个程序也配对失败,返回 0
                return 0;
            
            // 如果方括号配对成功则继续比较下一个字符
            i++;
        
        // 如果是右花括号
        else if (arr[i] == '') 
            // 获取栈顶元素
            getTop(stack, &top);
            // 如果栈顶元素是花括号,则正好配对 
            if (top == '') 
                // 则将栈顶元素出栈
                pop(&stack, &top);
             else 
                // 如果不是则一定不配对,那么整个程序也配对失败,返回 0
                return 0;
            
            // 如果花括号配对成功则继续比较下一个字符
            i++;
        
        // 如果是其他字符,则跳过继续比较判断下一个字符
        else 
            i++;
        
    

    // 循环结束后,如果栈为空则表示所有括号配对成功;如果栈非空,则栈中一定还有左括号,那么配对失败
    if (isEmpty(stack)) 
        return 1;
     else 
        return 0;
    

完整代码:

#include <stdio.h>

/**
 * 顺序栈最大存储的元素个数
 */
#define MAXSIZE 100

/**
 * 顺序栈结构体定义
 */
typedef struct 
    /**
     * 数据域,数组,用来存储栈中元素
     */
    char data[MAXSIZE];
    /**
     * 指针域,表示栈顶指针,实际上就是数组下标
     */
    int top;
 SeqStack;

/**
 * 初始化顺序栈,即将栈顶指针指向 -1 表示空栈
 * @param stack 顺序栈
 */
void init(SeqStack *stack) 
    // 设定让栈顶指针指向 -1 表示为栈空
    stack->top = -1;


/**
 * 判断顺序栈是否为空
 * @param stack 顺序栈
 * @return 如果顺序栈为空则返回 1,否则返回 0
 */
int isEmpty(SeqStack stack) 
    // 只需要判断栈顶指针是否等于 -1 即可,如果是空栈则返回 1,不是空栈则返回 0
    if (stack.top == -1) 
        return 1;
     else 
        return 0;
    


/**
 * 将元素入栈
 * @param stack 顺序栈
 * @param ele 元素值
 * @return 如果栈满则返回 0 表示入栈失败;如果插入成功则返回 1
 */
int push(SeqStack *stack, char ele) 
    // 1.参数校验,如果栈满则不能入栈元素
    if (stack->top == MAXSIZE - 1) 
        // 如果栈满,则返回 0,表示不能入栈
        return 0;
    
    // 2.先将栈顶指针加一,指向新空数组位置
    stack->top++;
    // 3.将新元素值填充到新位置中
    stack->data[stack->top] = ele;
    return 1;


/**
 * 将元素出栈
 * @param stack 顺序栈
 * @param ele 用来保存出栈的元素
 * @return 如果栈空则返回 0 表示出栈失败;否则返回 1 表示出栈成功
 */
int pop(SeqStack *stack, char *ele) 
    // 1.参数校验,栈空不能出栈
    if (stack->top == -1) 
        // 栈空,没有元素可出栈
        return 0;
    
    // 2.用 ele 来保存顺序栈栈顶元素
    *ele = stack->data[stack->top];
    // 3.然后栈顶指针减一,表示出栈一个元素
    stack->top--;
    return 1;


/**
 * 获取栈顶元素,但不出栈
 * @param stack 顺序栈
 * @param ele 用来保存出栈元素
 * @return 如果栈空则返回 0 表示出栈失败;否则返回 1 表示出栈成功
 */
int getTop(SeqStack stack, char *ele) 
    // 1.参数校验,如果栈空则不能出栈
    if (stack.top == -1) 
        // 栈空,没有元素可出栈
        return 0;
    
    // 2.保存栈顶元素返回
    *ele = stack.data[stack.top];
    return 1;


/**
 * 判断字符数组中的括号是否配对
 * @param arr 字符数组
 * @param n 数组长度
 * @return 如果所有括号配对成功则返回 1,否则返回 0 表示不匹配
 */
int isMatch(char arr[], int n) 
    // 声明栈并初始化,作为辅助解题数据结构使用
    SeqStack stack;
    init(&stack);

    // 变量,存放栈顶元素
    char top;

    // 变量,记录字符数组下标
    int i = 0;
    // 循环遍历包含括号的字符数组中的每个字符
    while (i < n) 
        // 为什么要用 ASCII 码值,因为不可能用一对单引号来引一个单引号字符,所以用数字来进行比较判断当前字符是否是单引号字符
        // 如果当前字符是单引号,则跳过一对单引号之后的所有字符,包括单引号本身
        if (arr[i] == 39) 
            // 跳过这对单引号中的第一个单引号
            i++;
            // 跳过单引号内的所有字符
            while (arr[i] != 39) 
                i++;
            
            // 跳过这对单引号中的最后一个单引号
            i++;
        
        // 如果当前字符是双引号,则跳过一对双引号之后的所有字符,包括双引号本身
        else if (arr[i] == 34) 
            // 跳过这对双引号中的第一个单引号
            i++;
            // 跳过双引号内的所有字符
            while (arr[i] != 34) 
                i++;
            
            // 跳过这对双引号中的最后一个双引号
            i++;
        
        // 如果是括号中的任何一个左括号
        else if (arr[i] == '(' || arr[i] == '[' || arr[i] == '') 
            // 将其存入栈中
            push(&stack, arr[i]);
            // 然后继续比较下一个字符
            i++;
        
        // 如果是右圆括号
        else if (arr[i] == ')') 
            // 获取栈顶元素
            getTop(stack, &top);
            // 如果栈顶元素是左圆括号,则正好配对 ()
            if (top == '(') 
                // 则将栈顶元素出栈
                pop(&stack, &top);
             else 
                // 如果不是则一定不配对,那么整个程序也配对失败,返回 0
                return 0;
            
            // 如果圆括号配对成功则继续比较下一个字符
            i++;
        
        // 如果是右方括号
        else if (arr[i] == ']') 
            // 获取栈顶元素
            getTop(stack, &top);
            // 如果栈顶元素是左方括号,则正好配对 []
            if (top == '[') 
                // 则将栈顶元素出栈
                pop(&stack, &top);
             else 
                // 如果不是则一定不配对,那么整个程序也配对失败,返回 0
                return 0;
            
            // 如果方括号配对成功则继续比较下一个字符
            i++;
        
        // 如果是右花括号
        else if (arr[i] == '') 
            // 获取栈顶元素
            getTop(stack, &top);
            // 如果栈顶元素是花括号,则正好配对 
            if (top == '') 
                // 则将栈顶元素出栈
                pop(&stack, &top);
             else 
                // 如果不是则一定不配对,那么整个程序也配对失败,返回 0
                return 0;
            
            // 如果花括号配对成功则继续比较下一个字符
            i++;
        
        // 如果是其他字符,则跳过继续比较判断下一个字符
        else 
            i++;
        
    

    // 循环结束后,如果栈为空则表示所有括号配对成功;如果栈非空,则栈中一定还有左括号,那么配对失败
    if (isEmpty(stack)) 
        return 1;
     else 
        return 0;
    


int main() 
    char arr[] = "a[c'ab[]',[(3[sdfe])345]aa]''";
    int n = 32;

    int match;
    match = isMatch(arr, n);
    printf("%s 中括号是否配对:%d", arr, match);

执行结果:

a[c'ab[]',[(3[sdfe])345]aa]'' 中括号是否配对:1

Java实现

核心代码:

    /**
     * 判断指定字符序列中的括号是否配对成功
     *
     * @param arr 字符序列
     * @return 如果配对成功则返回 1,否则返回 0 表示失败
     * @throws Exception 如果栈满再入栈则抛出异常
     */
    public static int isMatch(char[] arr) throws Exception 
        // 声明栈并初始化,作为辅助解题数据结构使用
        SeqStack stack = new SeqStack();
        stack.init();

        // 变量,存放栈顶元素
        char top;

        // 变量,记录字符数组下标
        int i = 0;
        // 变量,即数组长度
        int n = arr.length;
        // 循环遍历包含括号的字符数组中的每个字符
        while (i < n) 
            // 为什么要用 ASCII 码值,因为不可能用一对单引号来引一个单引号字符,所以用数字来进行比较判断当前字符是否是单引号字符
            // 如果当前字符是单引号,则跳过一对单引号之后的所有字符,包括单引号本身
            if (arr[i] == 39) 
                // 跳过这对单引号中的第一个单引号
                i++;
                // 跳过单引号内的所有字符
                while (arr[i] != 39) 
                    i++;
                
                // 跳过这对单引号中的最后一个单引号
                i++;
            
            // 如果当前字符是双引号,则跳过一对双引号之后的所有字符,包括双引号本身
            else if (arr[i] == 34) 
                // 跳过这对双引号中的第一个单引号
                i++;
                // 跳过双引号内的所有字符
                while (arr[i] != 34) 
                    i++;
                
                // 跳过这对双引号中的最后一个双引号
                i++;
            
            // 如果是括号中的任何一个左括号
            else if (arr[i] == '(' || arr[i] == '[' || arr[i] == '') 
                // 将其存入栈中
                stack.push(arr[i]);
                // 然后继续比较下一个字符
                i++;
            
            // 如果是右圆括号
            else if (arr[i] == ')') 
                // 获取栈顶元素
                top = stack.getTop();
                // 如果栈顶元素是左圆括号,则正好配对 ()
                if (top == '(') 
                    // 则将栈顶元素出栈
                    stack.pop();
                 else 
                    // 如果不是则一定不配对,那么整个程序也配对失败,返回 0
                    return 0;
                
                // 如果圆括号配对成功则继续比较下一个字符
                i++;
            
            // 如果是右方括号
            else if (arr[i] == ']') 
                // 获取栈顶元素
                top = stack.getTop();
                // 如果栈顶元素是左方括号,则正好配对 []
                if (top == '[') 
                    // 则将栈顶元素出栈
                    stack.pop();
                 else 
                    // 如果不是则一定不配对,那么整个程序也配对失败,返回 0
                    return 0;
                
                // 如果方括号配对成功则继续比较下一个字符
                i++;
            
            // 如果是右花括号
            else if (arr[i] == '') 
                // 获取栈顶元素
                top = stack.getTop();
                // 如果栈顶元素是花括号,则正好配对 
                if (top == '') 
                    // 则将栈顶元素出栈
                    stack.pop();
                 else 
                    // 如果不是则一定不配对,那么整个程序也配对失败,返回 0
                    return 0;
                
                // 如果花括号配对成功则继续比较下一个字符
                i++;
            
            // 如果是其他字符,则跳过继续比较判断下一个字符
            else 
                i++;
            
        

        // 循环结束后,如果栈为空则表示所有括号配对成功;如果栈非空,则栈中一定还有左括号,那么配对失败
        if (stack栈练习之Example002-求后缀式的数值

栈练习之Example007-利用栈判定单链表是否中心对称

栈练习之Example003-用不带头结点的单链表存储链栈并实现栈相关算法

栈练习之Example004-顺序栈 s0 和 s1 共享一个存储区 elem,设计共享栈关于入栈和出栈操作的算法

栈练习之Example006-判定给定的由 I 和 O 组成的入栈和出栈组成的操作序列是否合法

队列练习之Example005-Q 是一个队列,S 是一个空栈,实现将队列中的元素逆置的算法