赞
踩
个人主页:
专栏:
目录
栈(Stack):是只允许在一端进行插入或删除的线性表。首先栈是一种线性表,但限定这种线性表只能在某一端进行插入和删除操作。
栈顶(Top):线性表允许进行插入删除的那一端。
栈底(Bottom):固定的,不允许进行插入和删除的另一端。
空栈:不含任何元素的空表。
栈被称为后进先出(Last In First Out)的线性表,简称LIFO结构,最后压入栈的元素会被最先弹出
了解了栈的功能后,让我们自己实现一个栈,完成下面栈的应用:平衡括号,以及实现一个简单计算器
在实际编程中,我们经常会嵌套使用括号,如“{}”、“[]”、“()”,如果括号太多,可能会出现括号不匹配的情况,比如“(as))”、“{(bcd})”等。现希望你们编写一个程序,判断输入的一段语句中的括号是否匹配。
注:必须使用栈来实现这一功能,栈类用链表或者数组实现。
可定义一个字典dir,用于字符匹配。map是STL的一个关联容器,它提供一对一的hash。第一个可以称为关键字(key),每个关键字只能在map中出现一次;第二个以称为该关键字的值(value)。
输入字符串s,s是由{},[],()以及数字、字母组成的字符串(全都是半角字符)。
若括号使用规范且匹配,输出“1”,否则输出“0”。
4Print(abc[0]+’This is a {}’)
1
遍历输入字符串:我们从头到尾遍历输入的字符串,每次取出一个字符进行处理
使用栈来跟踪括号的匹配情况:我们使用栈来存储遇到的左括号,每当遇到一个右括号时,就检查栈顶的左括号是否与之匹配。如果匹配,则继续处理,如果不匹配,则括号不匹配
处理括号:当我们遇到左括号时,将其压入栈中;当遇到右括号时,检查栈顶的左括号是否与之匹配。如果匹配,则继续处理下一个字符;如果不匹配,则括号不匹配
检查栈的状态:最后,检查栈是否为空。如果为空,则表示所有左括号都有相应的右括号与之匹配,返回True;如果栈不为空,则表示某些左括号没有相应的右括号与之匹配,返回False
如上图,先将左括号“{”和“(”入栈,当遇到“)”时,弹出栈顶元素“(”,再依次入栈“[”、“(”、“{”,遇到“}”,“)”,“]”,“}”依次弹出栈顶元素进行匹配,最后判断出栈为空,则该括号匹配
结点类包含数据以及next指针,指向下一个结点
- struct Node
- {
- char data;
- Node* next;
- };
栈只需要一个栈顶指针head以及size用来记录栈的大小,初始化时将栈顶指针指向空指针,size置为0,析构函数中则清空栈中所有的元素,回收栈空间
- class Mystack {
- private:
- struct Node
- {
- char data;
- Node* next;
- };
-
- public:
- Node* head; // 栈顶指针
- int size; // 栈大小
-
- Mystack()
- {
- head = nullptr;
- size = 0;
- }; // 初始化空间
-
- ~Mystack()
- {
- Node* q = new Node;
- while (head != nullptr)
- {
- q = head;
- head = head->next;
- delete q;
- }
- } // 回收栈空间
- }
入栈操作,将一个元素压入栈顶,新节点的next指向原栈顶节点,然后更新栈顶指针head,栈的大小size+1
- void push(char elem) {
- Node* tmp = new Node();
- tmp->data = elem;
- size = size + 1;
- tmp->next = head;
- head = tmp;
- };
出栈操作,删除栈顶节点,释放其内存,更新栈顶指针head,栈大小size-1
- void pop() {
- if (head == nullptr) {
- return;
- }
- Node* tmp = head;
- head = head->next;
- delete tmp;
- size = size - 1;
- };
Symbol_matching函数用于判断输入的字符串中的括号是否匹配
首先定义一个映射表map<char, char> dic,用于存储括号的匹配关系,左括号作为键,右括号作为值,然后遍历字符串的每个字符,如果当前字符是左括号,将其入栈,如果当前字符是右括号,则需进行匹配。每次匹配时,检查栈是否为空,或者栈顶左括号与当前右括号是否匹配,如果不匹配,则返回 false。 如果匹配,则将栈顶左括号出栈。 最后,判断栈是否为空,如果栈为空则表示所有左括号都有相应的右括号与之匹配,返回 true;否则返回 false
- bool Symbol_matching(string str) {
- Mystack stack;
- map<char, char> dic = { {'{','}'}, {'[',']'}, {'(',')'} };
- for (char c : str)
- {
- if (dic.count(c))
- {
- stack.push(c);
- }
- else if (c == '}' || c == ']' || c == ')')
- {
- if (stack.size == 0 || dic[stack.head->data] != c) {
- return false;
- }
- else {
- stack.pop();
- }
- }
- }
- return stack.size == 0;
- }
- #include <iostream>
- #include <string>
- #include <map>
- using namespace std;
-
- class Mystack {
- private:
- struct Node
- {
- char data;
- Node* next;
- };
-
- public:
- Node* head; //栈顶指针
- int size; //栈大小
-
- Mystack()
- {
- head = nullptr;
- size = 0;
- }; //初始化空间
-
- ~Mystack()
- {
- Node* q = new Node;
- while (head != nullptr)
- {
- q = head;
- head = head->next;
- delete q;
- }
- } //回收栈空间
-
- void push(char elem) {
- //请完成入栈函数代码
- Node* tmp = new Node();
- tmp->data = elem;
- size = size + 1;
- tmp->next = head;
- head = tmp;
- };
-
- void pop() {
- if (head == nullptr) {
- return;
- }
- //请完成出栈函数代码
- Node* tmp =head;
- head = head->next;
- delete tmp;
- size = size - 1;
- };
-
- };
- bool Symbol_matching(string str) {
- Mystack stack;
- map<char, char> dic = { {'{','}'}, {'[',']'}, {'(',')'} };
- for (char c : str)
- {
- if (dic.count(c))
- {
- stack.push(c);
- }
- else if (c == '}' || c == ']' || c == ')')
- {
- if (stack.size == 0 || dic[stack.head->data] != c) {
- return false;
- }
- else {
- stack.pop();
- }
- }
- }
- return stack.size == 0;
- }
-
- int main() {
- string str;
- bool R;
- getline(cin, str);
- R = Symbol_matching(str);
- cout << R << endl;
- return 0;
- }
在了解问题二的内容之前,我们先来学习一下三种表达式
操作符以中缀形式位于运算数中间(如:3+2),是我们日常通用的算术和逻辑公式表示方法。
又称逆波兰式(Reverse Polish Notation - RPN),操作符以后缀形式位于两个运算数后(如:3+2的后缀表达形式就是3 2 +)。
又称波兰式(Polish Notation),操作符以前缀形式位于两个运算数前(如:3+2的前缀表达形式就是+ 3 2)
参考链接:《数据结构》:中缀表达式转后缀表达式 + 后缀表达式的计算-CSDN博客
从左至右依次遍历中缀表达式各个字符(需要准备一个字符栈存储操作符和括号)
1、字符为运算数 :
直接送入后缀表达式(注:需要先分析出完整的运算数)。
2、字符为左括号 :
直接入栈(注:左括号入栈后优先级降至最低)。
3、字符为右括号 :
直接出栈,并将出栈字符依次送入后缀表达式,直到栈顶字符为左括号(左括号也要出栈,但不送入后缀表达式)。
总结:只要满足 栈顶为左括号 即可进行最后一次出栈。
4、字符为操作符 :
若栈空,直接入栈。
若栈非空,判断栈顶操作符,若栈顶操作符优先级低于该操作符,该操作符入栈;否则一直出栈,并将出栈字符依次送入后缀表达式,直到栈空或栈顶操作符优先级低于该操作符,该操作符再入栈。
总结:只要满足 栈空 或者 优先级高于栈顶操作符 即可停止出栈,并将该操作符入栈。
5、重复以上步骤直至遍历完成中缀表达式,接着判断字符栈是否为空,非空则直接出栈,并将出栈字符依次送入后缀表达式。
注:中缀表达式遍历完成,栈中可能还有字符未输出,故需要判断栈空。
编写程序,输入一个中缀表达式,最长可容纳80个字符。计算的对象为数据类型为int的正整数,能计算加、减、乘、除,允许使用括号改变优先级。
输入一个中缀表达式。(字符串形式,全都是半角符号)
输出中缀表达式的计算结果
(2+3)+(2/3)+(2-3)+(2*3)
10
首先我们需要使用两个栈,一个存放操作数operands,一个存放运算符operators
然后遍历中缀表达式字符串读取每个字符,并结合栈来处理运算符和操作数。
1、如果是数字,则将其转换为整数,并将其压入操作数栈中。
2、如果是左括号 (,则将其压入运算符栈中。 如果是右括号 ),则执行栈内运算直到遇到匹配的左括号 (,并将结果压入操作数栈中。
3、如果是运算符 + - * /,则根据运算符的优先级决定是否进行运算,并将结果压入操作数栈中。
在遍历完所有字符后,如果运算符栈中还有运算符,则依次执行栈内运算,直到栈为空为止。
最后返回操作数栈中的唯一元素,即为中缀表达式的值
这里我们#include<stack>,引入stack库,故不需要重新定义结点类以及栈
我们定义int evaluate(int left, int right, char op) ,用来得到两个数和对应操作符的计算结果并返回
- int evaluate(int left, int right, char op) {
- switch (op) {
- case '+':
- return left + right;
- case '-':
- return left - right;
- case '*':
- return left * right;
- case '/':
- return left / right;
- default:
- return 0;
- }
- }
然后我们需要定义precedence(char op),用来判断运算符的优先级,若为乘除则返回2(即优先级最高),若为加减则返回1
- int precedence(char op) {
- if (op == '*' || op == '/') {
- return 2;
- } else if (op == '+' || op == '-') {
- return 1;
- } else {
- return 0;
- }
- }
准备工作完成后,我们需要自定义evaluateExpression函数用来计算中缀表达式
在函数开始时,创建两个栈,一个用于存放操作数 operands,另一个用于存放运算符 operators
遍历输入的中缀表达式expr中的每个字符。每次处理表达式中的一个字符
1、处理操作数: 如果当前字符是数字,表示操作数,则将其转换为整数并压入操作数栈 operands 中。 如果当前字符是一个多位数,则继续读取后续字符直到遇到非数字字符,将其合并成一个完整的操作数。
2、处理左括号: 如果当前字符是左括号"(",则将其压入运算符栈 operators 中。
3、处理右括号: 如果当前字符是右括号")",则执行栈内运算直到遇到匹配的左括号 (,具体操作是:弹出运算符栈顶的运算符,直到遇到左括号"("。每次弹出运算符时,同时从操作数栈中弹出两个操作数,将它们和运算符进行计算,结果压入操作数栈中。 弹出左括号"(",但不输出到结果。
4、处理运算符: 如果当前字符是运算符 + - * /,则根据其优先级和栈顶运算符的优先级进行比较:如果运算符栈为空,或者当前运算符优先级高于栈顶运算符优先级,则将当前运算符压入运算符栈中。 否则,不断地弹出运算符栈顶运算符直到满足上述条件,并将其压入操作数栈中。
在遍历完所有字符后,如果运算符栈中还有运算符,则依次执行栈内运算,直到栈为空为止
最后返回操作数栈顶的元素,即为中缀表达式的值。
- int evaluateExpression(const string& expr) {
- stack<int> operands;
- stack<char> operators;
-
- for (int i = 0; i < expr.length(); i++) {
- char c = expr[i];
-
- if (isdigit(c)) {
- int num = c - '0';
- while (i + 1 < expr.length() && isdigit(expr[i + 1])) {
- num = num * 10 + (expr[i + 1] - '0');
- i++;
- }
- operands.push(num);
- } else if (c == '(') {
- operators.push(c);
- } else if (c == ')') {
- while (!operators.empty() && operators.top() != '(') {
- char op = operators.top();
- operators.pop();
- int right = operands.top();
- operands.pop();
- int left = operands.top();
- operands.pop();
- operands.push(evaluate(left, right, op));
- }
- operators.pop();
- } else if (c == '+' || c == '-' || c == '*' || c == '/') {
- while (!operators.empty() && precedence(operators.top()) >= precedence(c)) {
- char op = operators.top();
- operators.pop();
- int right = operands.top();
- operands.pop();
- int left = operands.top();
- operands.pop();
- operands.push(evaluate(left, right, op));
- }
- operators.push(c);
- }
- }
- while (!operators.empty()) {
- char op = operators.top();
- operators.pop();
- int right = operands.top();
- operands.pop();
- int left = operands.top();
- operands.pop();
- operands.push(evaluate(left, right, op));
- }
-
- return operands.top();
- }
- #include <iostream>
- #include <stack>
- #include <string>
- #include <cctype>
-
- using namespace std;
-
- int precedence(char op) {
- if (op == '*' || op == '/') {
- return 2;
- } else if (op == '+' || op == '-') {
- return 1;
- } else {
- return 0;
- }
- }
-
- int evaluate(int left, int right, char op) {
- switch (op) {
- case '+':
- return left + right;
- case '-':
- return left - right;
- case '*':
- return left * right;
- case '/':
- return left / right;
- default:
- return 0;
- }
- }
-
- int evaluateExpression(const string& expr) {
- stack<int> operands;
- stack<char> operators;
-
- for (int i = 0; i < expr.length(); i++) {
- char c = expr[i];
-
- if (isdigit(c)) {
- int num = c - '0';
- while (i + 1 < expr.length() && isdigit(expr[i + 1])) {
- num = num * 10 + (expr[i + 1] - '0');
- i++;
- }
- operands.push(num);
- } else if (c == '(') {
- operators.push(c);
- } else if (c == ')') {
- while (!operators.empty() && operators.top() != '(') {
- char op = operators.top();
- operators.pop();
- int right = operands.top();
- operands.pop();
- int left = operands.top();
- operands.pop();
- operands.push(evaluate(left, right, op));
- }
- operators.pop();
- } else if (c == '+' || c == '-' || c == '*' || c == '/') {
- while (!operators.empty() && precedence(operators.top()) >= precedence(c)) {
- char op = operators.top();
- operators.pop();
- int right = operands.top();
- operands.pop();
- int left = operands.top();
- operands.pop();
- operands.push(evaluate(left, right, op));
- }
- operators.push(c);
- }
- }
- while (!operators.empty()) {
- char op = operators.top();
- operators.pop();
- int right = operands.top();
- operands.pop();
- int left = operands.top();
- operands.pop();
- operands.push(evaluate(left, right, op));
- }
-
- return operands.top();
- }
-
- int main() {
- string expr;
- getline(cin, expr);
-
- int result = evaluateExpression(expr);
- cout << result << endl;
-
- return 0;
- }
链接:
链接:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。