文章目录
一、链栈简介
栈是一种 操作受限 的特殊的线性表,属于逻辑结构。
操作受限是指只允许在一端(栈顶)进行插入或删除的操作。
栈的特点有:
- 后进先出,Last In First Out ,简写为 LIFO。
- 不同元素进栈的出栈排列符合Catalan数。
Catalan 数 即 卡特兰数,公式 1 n + 1 C 2 n n \frac{1}{n+1}C^{n}_{2n} n+11C2nn ,这个在选择题中经常出现。
栈通常有两种实现的存储结构:顺序存储和链式存储。
顺序存储:使用数组(地址连续的存储单元)+一个top指针来表示。
链式存储:使用多个带数据域和指针域的结点来表示。
而链栈则是指用 链式 的存储结构实现的栈结构。
以上两种存储方式在实现的过程中,有带头节点和不带头节点之分,这里实现的是带头结点的链栈。
二、链栈的代码实现
// 带头结点的链栈
typedef struct LinkNode{
char data;
struct LinkNode *next;
} *LinkStack;
// 初始化
bool InitStack(LinkStack &S){
S = (LinkNode *) malloc(sizeof(LinkNode));
if(S == NULL) return false; // 内存空间不足
S->next = NULL;
return S;
}
// 创建链栈
LinkStack createLinkStack(){
// 创建头节点
LinkNode * head = (LinkNode *) malloc(sizeof(LinkNode));
InitStack(head);
return head;
}
// 判断是否为空
bool StackEmpty(LinkStack &S){
return S == NULL || S->next == NULL;
}
// 入栈
bool Push(LinkStack &S, char x){
LinkNode *node = (LinkNode*) malloc(sizeof(LinkNode));
if(node == NULL) return false; // 内存空间不足
node -> data = x;
node -> next = S -> next;
S->next = node;
return true;
}
// 出栈
bool Pop(LinkStack &S, char &x){
if(StackEmpty(S)) return false; // 空栈
LinkNode *p = S -> next;
x = p -> data;
S -> next = p -> next;
free(p);
return true;
}
// 取栈顶元素
bool GetTop(LinkStack &s, char &x){
if(StackEmpty(s)) return false;
x = s->next->data;
return true;
}
三、栈的应用之括号匹配
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。
Leetcode 上的题目只需要实现特定的函数,为了练习,可以先实现一个程序,然后把核心的运算放到函数里。
3.1 思路描述
题目只需要让我们实现一个程序去匹配左右括号是否匹配,就跟写数学公式一样,一个标准的数学式子如果有左右括号,那么一定就是匹配的。
括号匹配一共分为两大类,N小类(N取决于括号的种类,题目中是3种)
(两大类是指左括号和右括号)
为方便描述,接下来暂时用 (
泛指所有左括号,)
泛指所有右括号
这里使用类似于消消乐的思想,遍历字符串然后逐一地将匹配的括号消去。
所以可以根据这两大类进行分类,(
直接存储,在遇到)
时在与(
进行对比,匹配时则消除(
。
例如