什么是栈?
栈有好几个意思,比如遵循先进后出规则的线性表(与“队列”相反);程序运行时系统分配变量地址空间的地方,遵循先进后出的原则(与“堆”相反);在CPU寄存器的一块存储介质,访问时遵循先进后出的原则
我们今天所说的栈,是第一个意思
什么是先进后出
先进后出,就是先进去的后出来。就这么简单。
比如我有数据x, y, z。我先把x放入栈,再把y放入栈,再把z放入栈。我想取出时,先取出z,再取出y,再取出x
这就是一个简单的示意图
入栈
入栈指数据存入
出栈
出栈指数据取出
C++给我们的栈
// 导入头文件
#include <stack>
// 栈在std命名空间里
using namespace std;
// 定义一个栈,栈里的每个元素是int类型的
stack<int> st;
// 将1入栈
st.push(1);
// 将2入栈
st.push(2);
// 返回栈顶
int tmp = st.top();
// 出栈,没有返回值
st.pop();
// 如果栈为空
if(st.empty());
什么是括号 :-)
括号分为小括号“()”,中括号“[]”,和大括号“{}”,其中每个括号分为左括号“([{”和右括号“}])”。每个左括号的后面都要有相同的右括号对应,而且括号不能错位。即可以([{}])而不能([{]})
什么是判断括号是否匹配
判断括号匹配就是判断括号的使用是否合理。具体怎么使用见《什么是括号》 :-)
怎么用栈判断括号是否匹配呢?
思路
用栈判断的思路是这样的:
1.遍历字符串
2.如果发现括号
1)判断是否为左括号
如果为左括号,则入栈
否则(为右括号),则出栈,并将取出结果与遍历到的括号比较,如果不是同一个类型的括号,直接返回-1 (表示错误)
3.遍历完毕,未发现错误,返回正确0 (表示正确)
代码实现
为(yin)了(wei)方(wo)便(bi)起(jiao)见(lan),这段代码写在了一个源文件里。实际开发中,应该要将类型的定义、函数的声明、头文件的包含等放在一个.h文件里,将功能函数放在一个.c的文件里,main函数放在main.c文件里。大家千万别学我这样只放在一个文件里哦
#include <stdio.h>
#include <stack>
#include <string.h>
// 定义括号类型的枚举
typedef enum{
LITTLE, // 小括号
MIDDLE, // 中括号
LARGE, // 大括号
ERROR // 错误
}brackets_t;
// 获取括号类型
brackets_t get_brackets_type(char c){
brackets_t result;
switch(c){
case '(':
case ')':
result = LITTLE;
break;
case '[':
case ']':
result = MIDDLE;
break;
case '{':
case '}':
result = LARGE;
break;
default:
result = ERROR;
break;
}
return result;
}
// 判断括号是否是左括号,是返回1
int is_left(char c){
if(c == '(' || c == '[' || c == '{')return 1;
return 0;
}
// 出栈 如果栈为空返回-1,否则返回栈顶元素
// 这句话定义了一个泛型(类型占位符),在编译过程中会将占位符改为具体类型
// 这个占位符就是T
template<class T>
T pop(std::stack<T> *st){
// 判断栈是否为空
if(!(*st).empty()){ // 不为空则正常调用
T result = (*st).top();
(*st).pop();
return result;
}
// 为空则返回T类型的-1
// 采用更厉害的强制转换
T *tmp; // 创建一个临时(T *)类型变量
int itmp = -1; // 创建一个临时int型变量
tmp = (T *)&itmp; // 让tmp存itmp的地址,需要进行强制转换
return *tmp; // 使用T的访问规则读取itmp的地址
}
// 判断括号组合是否正确,正确返回0
int is_brackets_right(const char *str){
std::stack<brackets_t> st; // 建立栈
// 遍历 字符串
int len = strlen(str);
for(int i = 0; i < len; i++){
// 存储当前括号的类型
brackets_t br = get_brackets_type(str[i]);
// 如果是括号 进行括号判断
if(br != ERROR){
// 如果当前括号是左括号
if(is_left(str[i]))
// 那么获取括号类型并存入栈
st.push(br);
//否则出栈并与当前括号比较类型
else {
// 出栈
brackets_t sr = pop<brackets_t>(&st);
// 如果类型不相等 返回-1
if(sr != br)return -1;
}
}
}
// 循环结束,如果没有问题,返回0
return 0;
}
int main(void){
char str[16];
scanf("%s", str);
int if_it = is_brackets_right(str);
if(if_it == 0)printf("It is right\n");
else printf("It is not right\n");
return 0;
}
这就是栈的初级用法——判断括号是否匹配