(本文除代码部分均为AI生成,我觉得AI写的还挺好的。)

大家好,欢迎来到我的技术博客!

今天我们开启一个新的系列——《栈》。作为第一集(EP1),我们将通过一个非常经典且实用的问题,来探索 C++std::stack 的强大之处:如何判断一个字符串中的符号是否正确配对?

这个问题在编程中无处不在,比如检查你写的代码中,那一层又一层的括号是否都正确闭合了。让我们开始吧!

问题:有效的括号

给定一个只包括 '('')''{''}''['']' 的字符串 s ,我们需要判断字符串是否“有效”。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。

例如,"()[]{}""{[]}" 都是有效的,而 "(]""([)]" 则是无效的。

我们的英雄:栈 (Stack)

要解决这个问题,我们需要请出我们的英雄——栈 (Stack)

栈是一种遵循“后进先出”(Last-In, First-Out, LIFO)原则的数据结构。你可以把它想象成一个只有一个开口的瓶子或者一摞盘子:你最后放进去的盘子,总是最先被拿出来。

这个特性完美地契合了括号配对的逻辑:最晚出现的左括号,应该最先被它对应的右括号配对并“消除”

C++ 实战代码

废话不多说,我们直接上代码。这是我们用C++ std::stack 实现的完整解决方案:

#include <string>
#include <iostream>
#include <stack>		// 包含栈的头文件

bool isValid(std::string s){		
	std::stack<char> parentheses;		// 创建名为parentheses,类型为char的栈。注意这里char要用<char>
	
	for(char c : s)		// C++特色,遍历字符串中的每个字符
	{
		if(c == '(' || c == '[' || c == '{'){
			parentheses.push(c);		// 左括号入栈!!!!!
		}
		else{		// 执行到这里说明c是右括号
			if(parentheses.empty()){
				return false;		// 此时栈里无元素,c无法与之配对,所以返回false
			}
			char top = parentheses.top();	// 栈里存在左括号,取最顶层的左括号
			
			if((top == '(' && c == ')' ) ||
			   (top == '[' && c == ']') ||
			   (top == '{' && c == '}'))
			{
				parentheses.pop();		// 左右括号成功配对,将栈顶的左括号“弹出”
			}
			else{
				return false;		// 配对失败返回false
			}
		}
	}
	return parentheses.empty();	// 到这一步说明字符串已经遍历完毕,最后检查是否有未配对的左括号。
									// 如果栈为空,说明全部配对成功,返回true;否则说明有剩余,返回false。
}

int main()
{
	std::string s1 = "[{}]";
	std::string s2 = "[[]}";
	std::cout << s1 << " is " << (isValid(s1) ? "true" : "false") << std::endl;
	std::cout << s2 << " is " << (isValid(s2) ? "true" : "false") << std::endl;
	return 0;
}

代码逻辑详解

  1. 引入头文件与创建栈 我们首先需要 #include <stack>。然后在函数 isValid 中,通过 std::stack<char> parentheses; 创建了一个专门存放字符的栈。

  2. 遍历字符串 for(char c : s) 是C++11引入的“基于范围的for循环”,它会帮我们依次取出字符串 s 中的每一个字符,非常方便。

  3. 遇到左括号:入栈c 是一个左括号 ((, [, {) 时,我们的策略很简单:把它推入(push)栈中。这就像在说:“嘿,我遇到了一个需要被匹配的左括号,先存起来等它的另一半”。

  4. 遇到右括号:核心匹配逻辑 这是算法最精彩的部分。当 c 是一个右括号时:
    • 检查栈是否为空if(parentheses.empty())。如果此时栈是空的,却来了一个右括号,说明这个右括号是多余的,根本没有左括号可以和它配对。直接判定为无效,返回 false
    • 查看栈顶元素:如果栈不空,我们用 parentheses.top() 方法看一眼栈顶的元素是什么,但不把它拿出来。
    • 判断是否配对:我们检查栈顶的左括号是否和当前的右括号是完美的一对。如果是,就调用 parentheses.pop() 将栈顶的左括号弹出,代表它们成功“抵消”了。
    • 配对失败:如果类型不匹配,说明字符串无效,返回 false
  5. 最后的检查 当整个字符串都遍历完毕后,我们还需要做最后一步检查:return parentheses.empty();
    • 如果此时栈是空的,说明所有左括号都被成功匹配并弹出了,字符串有效,函数返回 true
    • 如果栈不是空的,说明还有多余的左括号(如 "(((" 这种情况)没有被匹配,字符串无效,函数返回 false

结语

通过这个例子,我们可以看到栈结构在处理具有“层级”或“配对”关系问题时的巨大威力。它清晰、高效地解决了括号匹配问题。

希望这篇 栈EP1 能帮助你更好地理解 std::stack 的使用。在下一集,我们或许可以探讨栈在其他场景下的更多应用,敬请期待!


PS:panda dev-c++复制单行代码可以按住ctrl点home和end键,然后复制。 然后我觉得我现在对于bool这块不是特别熟。