目录
1 问题背景
栈的括号匹配问题是指在给定一个字符串(包含多种括号),判断其中的括号是否能够正确匹配,即每个左括号是否有一个对应的右括号与之匹配,并且左右括号必须以正确的顺序进行匹配。
例如,字符串"((()))"中的括号就能够正确匹配,而字符串"()())"中的括号就无法正确匹配。
2 具体思路
这是王道给出的流程图:
看起来有点吃力,我来总结一下,很简单,就几步:
- 遍历给定的字符串,对于每个字符进行判断。
- 如果字符是左括号,将其入栈。
- 如果字符是右括号,将其与栈顶元素作比较,判断该元素是否是与之匹配的左括号。如果是,弹出栈顶元素,并继续遍历;如果不是,说明括号不匹配,返回false。
- 如果字符串遍历完毕,栈为空,则说明全部括号匹配,返回true;否则,返回false。
注意如果在准备弹出元素时发现栈已为空,说明前面没有左括号与该右括号匹配,返回false。
3 代码实现
以Acwing上一道例题举例:3693. 括号匹配 - AcWing题库
输入格式
共一行,包含一个由 `<`,`(`,`{`,`[`,`>`,`)`,`}`,`]` 构成的字符串。
输出格式
如果输入的字符串中的括号正确匹配则输出 `yes`,否则输出 `no`。
数据范围
输入字符串长度不超过 10000。
输入样例:
(){}
输出样例:
yes
3.1 顺序栈实现
#include<stdio.h>
#include<string.h>
#include<stdbool.h> //C语言引入该库才有bool值
#define MAX_SIZE 100000 //定义栈中元素的最大个数
typedef struct {
int data[MAX_SIZE]; //静态数组存放栈中元素
int top; //栈顶指针
} SqStack;
//初始化栈
void initStack(SqStack *s) {
s->top = -1;
}
//判断栈空
bool stackEmpty(SqStack s) {
return s.top == -1; //如果栈是空的,那么就会返回true
}
//新元素入栈
bool push(SqStack *s, int x) {
if (s->top == MAX_SIZE - 1) //如果栈已满,返回false
return false;
s->data[++(s->top)] = x; //否则先将栈顶指针的值加1,然后再使用增加后的栈顶指针指向的位置作为数组下标,将x存储到data数组中
return true;
}
//出栈
bool pop(SqStack *s, int *x) {
if (s->top == -1) { //因为栈已空,再出栈报错返回false
return false;
}
*x = s->data[s->top--]; //从栈顶取出一个元素并赋值给x*,然后将栈顶指针减1,即把栈顶指针指向它下方的元素
/*为什么给x*呢?因为需要通过指针参数才能把栈的元素值传递出去,进而传给topElem*/
return true;
}
//括号匹配算法的主体
bool bracketCheck(char str[]) {
SqStack s;
initStack(&s);
for (int i = 0; i < strlen(str); i++) {
if (str[i] == '<' || str[i] == '(' || str[i] == '{' || str[i] == '[') {
push(&s, str[i]);
} else {
if (stackEmpty(s)) {
return false;
}
int topElem; //topElem作为中间变量,记录从栈中弹出的栈顶元素
if (!pop(&s, &topElem)) { //如果取出栈顶元素失败,说明栈为空,则匹配失败,返回false
return false;
}
if (str[i] == '>' && topElem != '<') {
return false;
}
if (str[i] == ')' && topElem != '(') {
return false;
}
if (str[i] == ']' && topElem != '[') {
return false;
}
if (str[i] == '}' && topElem != '{') {
return false;
}
}
}
return stackEmpty(s); //栈空,说明所有括号都能匹配成功,返回true;否则说明还有没配成功的括号,返回false
}
int main() {
char str[MAX_SIZE]; //接收字符串
scanf("%s", str);
if (bracketCheck(str)) printf("yes");
else printf("no");
return 0;
}
3.2 链栈实现
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
} Node;
typedef struct {
Node* top;
int count;
} LinkedStack;
// 初始化链栈
void InitStack(LinkedStack* S) {
S->top = NULL;
S->count = 0;
}
// 判断栈空
bool StackEmpty(LinkedStack* S) {
return S->count == 0;
}
// 新元素入栈
bool Push(LinkedStack* S, int x) {
Node* node = (Node*)malloc(sizeof(Node));
if (node == NULL) {
return false; // 内存分配失败,入栈失败
}
node->data = x;
node->next = S->top;
S->top = node;
S->count++;
return true;
}
// 弹出栈顶元素
bool Pop(LinkedStack* S, int* x) {
if (StackEmpty(S)) {
return false; // 栈空,弹出失败
}
Node* node = S->top;
S->top = node->next;
*x = node->data;
free(node);
S->count--;
return true;
}
// 读取栈顶元素
bool GetTop(LinkedStack* S, int* x) {
if (StackEmpty(S)) {
return false; // 栈空,读取失败
}
*x = S->top->data;
return true;
}
// 括号匹配检查
bool bracketCheck(char str[]) {
LinkedStack S;
InitStack(&S);
for (int i = 0; i < strlen(str); i++) {
if (str[i] == '<' || str[i] == '(' || str[i] == '{' || str[i] == '[') {
Push(&S, str[i]);
} else {
if (StackEmpty(&S)) {
return false; // 栈空,匹配失败
}
int topElem;
if (!Pop(&S, &topElem)) {
return false; // 弹出失败,匹配失败
}
if (str[i] == '>' && topElem != '<') {
return false; // 匹配失败
}
if (str[i] == ')' && topElem != '(') {
return false; // 匹配失败
}
if (str[i] == ']' && topElem != '[') {
return false; // 匹配失败
}
if (str[i] == '}' && topElem != '{') {
return false; // 匹配失败
}
}
}
return StackEmpty(&S);
}
int main() {
char str[100000];
scanf("%s", str);
if (bracketCheck(str)) {
printf("yes\n");
} else {
printf("no\n");
}
return 0;
}