20. 有效的括号 - 力扣(LeetCode)
c++有栈 但是C语言没有
到那时我们可以自己造
这里的代码是直接调用栈,然后调用
等于三个左括号的任意一个 我们就入栈
左括号(入栈)
右括号
取出栈顶数据,出栈并且进行匹配,这里匹配的是不匹配的情况
这里进行方向的判断
因为不匹配可以直接拿结果
栈里面还有数据意味着数量不相等
‘也就是此时进行判断 此时栈是不是为空
图解
- 因为每次都是左括号入栈,然后然后才有右括号的,所以我们可以来一个判断,如果入栈半天只有左括号,那么说明也就是第四种情况,直接返回fash就可以
- 根据栈的性质,先进先出,我们可以把输入数值的左括号入栈,因为匹配的时候,我们不能去寻找与之匹配的右括号,因为这样可能存在漏掉某一个数组里面的数组就像第三个,所以我们需要进行遍历,所有的左括号入栈,因为的对称的,所以我们可以判定哪些不是与之匹配的右括号,不是就false(这期间记得每次匹配之后,我们需要进行出栈,也就是让栈的第一个数值进行更换,因为我们已经参与匹配并且成功了)
- 循环结束之后此时我们进行一个判空,如果是空的说明是,满足条件的,不是空的说明是不满足条件的
代码的实现
#pragma once #include <assert.h> #include <stdio.h> #include <stdlib.h> typedef char STDataType; typedef struct Stack { STDataType* _a; // 首元素的地址 int _top; // 栈顶,初始化为0,也就是等同于size,初始化为-1,等同于下标 int _capacity; // 容量 } Stack; // 初始化栈 void StackInit(Stack* ps); // 销毁栈 void StackDestroy(Stack* ps); // 入栈 void StackPush(Stack* ps, STDataType data); // 出栈 void StackPop(Stack* ps); // 获取栈顶元素 STDataType StackTop(Stack* ps); // 获取栈中有效元素个数 int StackSize(Stack* ps); // 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 int StackEmpty(Stack* ps); // 初始化栈 void StackInit(Stack* ps) { ps->_a = NULL; // 这里栈顶初始化为-1和初始化为0是不一样的 // 0 0 0 0 0 0 0 0 数组 // -1 0 0 0 0 0 0 0 0 初始化为-1 // 0 0 0 0 0 0 0 0 初始化为0 // 初始化为0,也就是等同于size,初始化为-1,等同于下标 ps->_capacity = ps->_top = 0; } // 销毁栈 void StackDestroy(Stack* ps) { // 判断为不为空,判断里面有没有数值 assert(ps && ps->_top); free(ps->_a); ps->_capacity = ps->_top = 0; } // 入栈 void StackPush(Stack* ps, STDataType data) { // 首先判断容量是多少,然后进行扩容 if (ps->_capacity == ps->_top) { // 扩容 int newapacity = ps->_capacity == 0 ? 4 : 2 * ps->_capacity; STDataType* tmp = (STDataType*)realloc(ps->_a, newapacity * sizeof(STDataType)); if (tmp == NULL) { perror("StackPush:tmp:error:"); exit(1); } // 改变容量大小,指向新空间的头第一个元素位置的地址 ps->_capacity = newapacity; ps->_a = tmp; } // 插入数值 ps->_a[ps->_top] = data; ps->_top++; } // 出栈 void StackPop(Stack* ps) { // 判断为不为空,判断里面有没有数值 assert(ps && ps->_top); ps->_top--; } // 获取栈顶元素 STDataType StackTop(Stack* ps) { assert(ps && ps->_top); return ps->_a[ps->_top - 1]; } // 获取栈中有效元素个数 int StackSize(Stack* ps) { assert(ps && ps->_top); return ps->_top - 1; } // 检测栈是否为空,如果为空返回非零结果(1),如果不为空返回0 int StackEmpty(Stack* ps) { assert(ps); return ps->_top == 0; // 所以,ps->_top == 0 这个表达式的作用是比较栈顶位置 ps->_top 是否等于 0。 // 如果相等,说明栈为空,表达式结果为 true(在C语言中用 1 表示); // 如果不相等,说明栈不为空,表达式结果为 false(在C语言中用 0 表示) } bool isValid(char* s) { // 创建变量 Stack ps; // 初始化变量 StackInit(&ps); while (*s) { // 给出入栈条件,左边括号进行入栈 if (*s == '[' || *s == '{' || *s == '(') { StackPush(&ps, *s); } else { if (StackEmpty(&ps)) { //StackDestroy(&ps); return false; } // 取栈顶 STDataType ch = StackTop(&ps); // 判断不匹配的条件 if (ch == '[' && *s != ']' || ch == '(' && *s != ')' || ch == '{' && *s != '}') { //StackDestroy(&ps); return false; } // 出栈 StackPop(&ps); } ++s; } // 检测栈是否为空,如果为空返回非零结果ture,如果不为空返回false bool ret = StackEmpty(&ps); return ret; }
解释:
栈结构体定义:
STDataType* _a
:指向栈数组的指针,用于存储栈中的元素。int _top
:表示栈顶的位置。数组索引从0开始,栈顶位置_top
初始化为0,表示栈为空。int _capacity
:栈的容量,用于存储栈中最多可以存放的元素数量。栈操作函数:
StackInit
:初始化栈,将数组指针设置为NULL
,栈顶_top
和容量_capacity
都设置为0。StackDestroy
:释放栈数组的内存,并将栈顶和容量重置为0。StackPush
:入栈操作,将元素添加到栈顶,如果栈已满则先进行扩容。StackPop
:出栈操作,移除栈顶的元素。StackTop
:获取栈顶元素的值。StackSize
:获取栈中元素的数量。StackEmpty
:检查栈是否为空。括号验证函数
isValid
:
- 该函数接收一个字符数组
s
作为参数,用于验证字符串中的括号是否正确配对。- 在函数内部,首先创建并初始化了一个
Stack
类型的变量ps
。- 然后,使用
while
循环遍历字符串s
:
- 如果当前字符是
[
、{
或(
(左括号),则将其入栈。- 如果当前字符是
]
、}
或)
(右括号):
- 首先检查栈是否为空。如果栈为空,说明没有对应的左括号与之配对,返回
false
。- 否则,获取栈顶元素并与当前字符配对检查。如果配对不成功,返回
false
。- 如果配对成功,执行出栈操作。
- 在循环结束后,检查栈是否为空。如果栈为空,则说明所有括号都正确配对,返回
true
;否则返回false
。括号配对规则:
- 每种左括号(
[
、{
、(
)必须与其对应的右括号(]
、}
、)
)配对。- 括号的配对必须遵守正确的嵌套顺序。
注意事项:
- 在
StackPush
函数中,使用了realloc
进行内存扩容。如果realloc
失败,程序将输出错误信息并退出。- 在
StackDestroy
函数中,使用assert
宏确保传入的栈指针ps
不是NULL
,并且栈是非空的。- 在
isValid
函数中,没有释放局部栈ps
的内存,因为ps
是自动变量,其内存会在函数结束时自动释放。如果ps
是动态分配的,那么需要在函数末尾调用StackDestroy
并传递ps
的地址。