栈是限定仅在表尾进行插入和删除操作的线性表。栈中的数据具有后入先出先出的性质,形象点比喻,栈就像手枪弹夹,而数据就像弹夹的子弹。
那么,如何用C语言来实现栈的结构呢?
用数组来表示栈,基本结构结构如下:
typedef int STDataType;
typedef struct Stack
{
STDataType* _a;
int _top; // 栈顶
int _capacity; // 容量
}Stack;
_top代表栈顶元素的下表,加一可表示栈内元素个数,_capacity代表数组容量,方便后面对栈的扩容,同时还一个栈还需要具备查询首元素,弹出首元素(出栈),添加元素(入栈),判定是否为空,获取有效元素个数,销毁栈等等方法,具体实现如下:
// 初始化栈
void StackInit(Stack* ps)
{
assert(ps);
ps->_a = NULL;
ps->_top = -1;
ps->_capacity = 0;
}
// 入栈
void StackPush(Stack* ps, STDataType data)
{
assert(ps);
if(ps->_top+1>=ps->_capacity)
{
ps->_a = (STDataType*)realloc(ps->_a, (4 + ps->_capacity) * sizeof(STDataType));
ps->_capacity += 4;
}
ps->_top++;
ps->_a[ps->_top] = data;
}
// 出栈
void StackPop(Stack* ps)
{
assert(ps);
assert(ps->_top>=0);
ps->_top--;
}
// 获取栈顶元素
STDataType StackTop(Stack* ps)
{
assert(ps);
assert(ps->_top >= 0);
return ps->_a[ps->_top];
}
// 获取栈中有效元素个数
int StackSize(Stack* ps)
{
return ps->_top + 1;
}
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps)
{
if (ps->_top == -1)
{
return -1;
}
return 0;
}
// 销毁栈
void StackDestroy(Stack* ps)
{
assert(ps);
free(ps->_a);
ps->_a = NULL;
ps->_top = -1;
ps->_capacity = 0;
}
现在我们制造了一个栈,不妨用它来解决一些问题来练练手吧!
括号匹配问题:判定给定字符串(只含“{}”,“[]”,"()"3种括号)中的括号是否匹配,若匹配返回true,不匹配返回false。(例:“{}{}[()]”为匹配,“[]{]][(())”为不匹配)
力扣链接:. - 力扣(LeetCode)
相关代码如下(别忘了把上面的栈结构复制上去和改STDataType哦~):
bool isValid(char* s)
{
Stack box;
StackInit(&box);
int i = 0;
while(s[i]!='\0')
{
if(s[i]=='{'||s[i]=='['||s[i]=='(')
{
StackPush(&box,s[i]);
}
else
{
if(box._top==-1)
{
return false;
}
char item = StackTop(&box);
if(item=='{'&&s[i]!='}'||
item=='['&&s[i]!=']'||
item=='('&&s[i]!=')')
{
return false;
}
else
{
StackPop(&box);
}
}
i++;
}
if(StackSize(&box)>0)
{
return false;
}
return true;
}
解题思路:设立一个栈,从头开始录入括号,括号为右括号时入栈,若遇到左括号时取栈顶元素比较,如果不是相应的右括号就直接判false(注:可能遇到栈空了遇到左括号的情况,需提前判定栈是否为空,如果在空的情况下遇到,直接判false),若是则继续,直到字符串走完。当字符串走完时,如果栈内已空,就可以放心返回true了,如果不为空,则是“[[{()}]”这种情况,直接返回false。