跳到主要内容C++反向迭代器实现与逆波兰表达式计算器 | 极客日志C++算法
C++反向迭代器实现与逆波兰表达式计算器
讲解 C++ 反向迭代器的底层原理与实现,涵盖 SGI-STL 源码分析及自定义 vector/list 适配。深入解析逆波兰表达式(后缀表达式)的运算机制,包括中缀转后缀算法及括号处理。结合栈结构实现基本计算器功能,解决负数、空格及优先级问题,提供完整 C++ 代码示例。
雾岛听风1.6K 浏览 C++反向迭代器实现与逆波兰表达式计算器
1. 反向迭代器思路 (源码及框架分析)
反向迭代器是一种特殊的迭代器,它的核心作用是:从容器的末尾开始,逆向遍历容器中的元素(正常迭代器是从头部到尾部)。可以把它理解成:
正常迭代器:像你从队伍第一个人走到最后一个人;
反向迭代器:像你从队伍最后一个人倒着走回第一个人。
SGI-STL30 版本源代码,反向迭代器实现的核心源码在 stl_iterator.h 中,反向迭代器是一个适配器,各个容器中再适配出自己的反向迭代器。下面我们截出 vector 和 list 的反向迭代器结构框架核心部分截取出来如下:
template <class T, class Alloc = alloc>
class list {
public:
typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<T, const T&, const T*> const_iterator;
#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
typedef reverse_iterator<const_iterator> const_reverse_iterator;
typedef reverse_iterator<iterator> reverse_iterator;
#else
typedef reverse_bidirectional_iterator<const_iterator, value_type, const_reference, difference_type> const_reverse_iterator;
typedef reverse_bidirectional_iterator<iterator, value_type, reference, difference_type> reverse_iterator;
#endif
iterator begin() { return (link_type)((*node).next); }
const_iterator begin() const { return (link_type)((*node).next); }
iterator end() { node; }
{ node; }
{ (()); }
{ (()); }
{ (()); }
{ (()); }
};
< , = alloc>
vector {
:
T value_type;
value_type* iterator;
reverse_iterator<const_iterator> const_reverse_iterator;
reverse_iterator<iterator> reverse_iterator;
reverse_iterator<const_iterator, value_type, const_reference, difference_type> const_reverse_iterator;
reverse_iterator<iterator, value_type, reference, difference_type> reverse_iterator;
{ start; }
{ start; }
{ finish; }
{ finish; }
{ (()); }
{ (()); }
{ (()); }
{ (()); }
};
< >
{
:
Iterator current;
:
iterator_traits<Iterator>::iterator_category iterator_category;
iterator_traits<Iterator>::value_type value_type;
iterator_traits<Iterator>::difference_type difference_type;
iterator_traits<Iterator>::pointer pointer;
iterator_traits<Iterator>::reference reference;
Iterator iterator_type;
reverse_iterator<Iterator> self;
:
() {}
}
( self& x) : (x.current) {}
< >
( reverse_iterator<Iter>& x) : (x.current) {}
{ current; }
reference *() { Iterator tmp = current; *--tmp; }
pointer ->() { &(*()); }
self& ++() { --current; *; }
self ++() { self tmp = *; --current; tmp; }
self& --() { ++current; *; }
self --() { self tmp = *; ++current; tmp; }
self +(difference_type n) { (current - n); }
self& +=(difference_type n) { current -= n; *; }
self -(difference_type n) { (current + n); }
self& -=(difference_type n) { current -= n; *; }
reference [](difference_type n) { *(* + n); }
};
< >
==( reverse_iterator<Iterator>& x, reverse_iterator<Iterator>& y) {
x.() == y.();
}
< >
<( reverse_iterator<Iterator>& x, reverse_iterator<Iterator>& y) {
y.() < x.();
}
< >
reverse_iterator<Iterator>::difference_type -( reverse_iterator<Iterator>& x, reverse_iterator<Iterator>& y) {
y.() - x.();
}
< >
reverse_iterator<Iterator> +(reverse_iterator<Iterator>::difference_type n, reverse_iterator<Iterator>& x) {
<Iterator>(x.() - n);
}
< , , = T&, Distance = >
reverse_bidirectional_iterator {
reverse_bidirectional_iterator<BidirectionalIterator, T, Reference, Distance> self;
:
BidirectionalIterator current;
:
bidirectional_iterator_tag iterator_category;
T value_type;
Distance difference_type;
T* pointer;
Reference reference;
() {}
}
{ current; }
Reference *() { BidirectionalIterator tmp = current; *--tmp; }
pointer ->() { &(*()); }
self& ++() { --current; *; }
self ++() { self tmp = *; --current; tmp; }
self& --() { ++current; *; }
self --() { self tmp = *; ++current; tmp; }
};
< , , = T&, Distance = >
reverse_iterator {
reverse_iterator<RandomAccessIterator, T, Reference, Distance> self;
:
RandomAccessIterator current;
:
random_access_iterator_tag iterator_category;
T value_type;
Distance difference_type;
T* pointer;
Reference reference;
() {}
}
{ current; }
Reference *() { *(current - ); }
pointer ->() { &(*()); }
self& ++() { --current; *; }
self ++() { self tmp = *; --current; tmp; }
self& --() { ++current; *; }
self --() { self tmp = *; ++current; tmp; }
self +(Distance n) { (current - n); }
self& +=(Distance n) { current -= n; *; }
self -(Distance n) { (current + n); }
self& -=(Distance n) { current -= n; *; }
Reference [](Distance n) { *(* + n); }
};
微信扫一扫,关注极客日志
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
- Markdown转HTML
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
- HTML转Markdown
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
- JSON 压缩
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
return
const_iterator end() const
return
reverse_iterator rbegin()
return
reverse_iterator
end
const_reverse_iterator rbegin() const
return
const_reverse_iterator
end
reverse_iterator rend()
return
reverse_iterator
begin
const_reverse_iterator rend() const
return
const_reverse_iterator
begin
template
class
T
class
Alloc
class
public
typedef
typedef
#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
typedef
typedef
#else
typedef
typedef
#endif
iterator begin()
return
const_iterator begin() const
return
iterator end()
return
const_iterator end() const
return
reverse_iterator rbegin()
return
reverse_iterator
end
const_reverse_iterator rbegin() const
return
const_reverse_iterator
end
reverse_iterator rend()
return
reverse_iterator
begin
const_reverse_iterator rend() const
return
const_reverse_iterator
begin
#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
template
class
Iterator
class
reverse_iterator
protected
public
typedef
typename
typedef
typename
typedef
typename
typedef
typename
typedef
typename
typedef
typedef
public
reverse_iterator
explicit reverse_iterator(iterator_type x) : current(x) {
reverse_iterator
const
current
#ifdef __STL_MEMBER_TEMPLATE
template
class
Iter
reverse_iterator
const
current
#endif
iterator_type base() const
return
operator
const
return
#ifndef __SGI_STL_NO_ARROW_OPERATOR
operator
const
return
operator
#endif
operator
return
this
operator
int
this
return
operator
return
this
operator
int
this
return
operator
const
return
self
operator
return
this
operator
const
return
self
operator
return
this
operator
const
return
this
template
class
Iterator
inline
bool
operator
const
const
return
base
base
template
class
Iterator
inline
bool
operator
const
const
return
base
base
template
class
Iterator
inline
typename
operator
const
const
return
base
base
template
class
Iterator
inline
operator
const
return
reverse_iterator
base
#else
template
class
BidirectionalIterator
class
T
class
Reference
class
ptrdiff_t
class
typedef
protected
public
typedef
typedef
typedef
typedef
typedef
reverse_bidirectional_iterator
explicit reverse_bidirectional_iterator(BidirectionalIterator x) : current(x) {
BidirectionalIterator base() const
return
operator
const
return
#ifndef __SGI_STL_NO_ARROW_OPERATOR
operator
const
return
operator
#endif
operator
return
this
operator
int
this
return
operator
return
this
operator
int
this
return
template
class
RandomAccessIterator
class
T
class
Reference
class
ptrdiff_t
class
typedef
protected
public
typedef
typedef
typedef
typedef
typedef
reverse_iterator
explicit reverse_iterator(RandomAccessIterator x) : current(x) {
RandomAccessIterator base() const
return
operator
const
return
1
#ifndef __SGI_STL_NO_ARROW_OPERATOR
operator
const
return
operator
#endif
operator
return
this
operator
int
this
return
operator
return
this
operator
int
this
return
operator
const
return
self
operator
return
this
operator
const
return
self
operator
return
this
operator
const
return
this
#endif
1️⃣ 源码中我们可以看到 reverse_iterator 实现了两个版本,通过 __STL_CLASS_PARTIAL_SPECIALIZATION 条件编译控制使用哪个版本,简单点说就是支持偏特化的迭代器萃取以后,反向迭代器使用的是这个版本 template <class reverse_iterator>;之前使用的是 template <class BidirectionalIterator, class T, class Reference, class Distance> class reverse_bidirectional_iterator 或 template <class RandomAccessIterator, class T, class Reference class Distance> class reverse_iterator。
2️⃣ 可以看到他们的差别主要是在模板参数是否传递迭代器指向的数据类型,支持偏特化的迭代器萃取以后就不需要给了,因为 reverse_iterator 内部可以通过迭代器萃取获取数据类型。迭代器萃取的本质是一个特化,这个还有些小复杂且不影响我们学习,这里我就不讲解了,有兴趣可以去看源码,这个我们主要使用模版参数传递数据类型的方式实现。
3️⃣ 反向迭代器本质上是一个适配器,使用模版实现,传递哪个容器的迭代器就可以封装适配出对应的反向迭代器。因为反向迭代器的功能跟正向的迭代器功能高度相似,只是遍历的方向相反,类似 operator++ 底层调用迭代器的 operator-- 等,所以封装一下就可以实现。
4️⃣ 比较奇怪的是 operator* 的实现,内部访问的是迭代器当前位置的前一个位置。这个要结合容器中 rbegin 和 rend 实现才能看懂,rbegin 返回的是封装 end 位置的反向迭代器,rend 返回的是封装 begin 位置迭代器的反向迭代器,这里是为了实现出一个对称,所以解引用访问的是当前位置的前一个位置。
2. 反向迭代器的实现
#pragma once
#include <iostream>
#include <cstdlib>
#include <algorithm>
using namespace std;
template <class T>
struct ListNode {
T _data;
ListNode<T>* _prev;
ListNode<T>* _next;
ListNode(const T& val = T()) : _data(val), _prev(nullptr), _next(nullptr) {}
};
template <class T, class Ref, class Ptr>
struct ListIterator {
typedef ListNode<T> Node;
typedef ListIterator<T, Ref, Ptr> Self;
Node* _node;
ListIterator(Node* node) : _node(node) {}
Ref operator*() const { return _node->_data; }
Ptr operator->() const { return &_node->_data; }
Self& operator++() { _node = _node->_next; return *this; }
Self operator++(int) { Self tmp(*this); _node = _node->_next; return tmp; }
Self& operator--() { _node = _node->_prev; return *this; }
Self operator--(int) { Self tmp(*this); _node = _node->_prev; return tmp; }
bool operator==(const Self& s) const { return _node == s._node; }
bool operator!=(const Self& s) const { return _node != s._node; }
};
#pragma once
#include "Common.h"
namespace lcz {
template <class Iterator, class Ref, class Ptr>
struct ReverseIterator {
typedef ReverseIterator<Iterator, Ref, Ptr> Self;
Iterator _it;
ReverseIterator(Iterator it) : _it(it) {}
Ref operator*() { Iterator tmp = _it; return *(--tmp); }
Ref operator*() const { Iterator tmp = _it; return *(--tmp); }
Ptr operator->() { return &(operator*()); }
Ptr operator->() const { return &(operator*()); }
Self& operator++() { --_it; return *this; }
Self operator++(int) { Self tmp(*this); --_it; return tmp; }
Self& operator--() { ++_it; return *this; }
Self operator--(int) { Self tmp(*this); ++_it; return tmp; }
bool operator!=(const Self& s) const { return _it != s._it; }
bool operator==(const Self& s) const { return _it == s._it; }
};
}
#pragma once
#include "ReverseIterator.h"
namespace lcz {
template <class T>
class vector {
public:
typedef T* iterator;
typedef const T* const_iterator;
typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
typedef ReverseIterator<const_iterator, const T&, const T*> const_reverse_iterator;
vector() : _start(nullptr), _finish(nullptr), _endofstorage(nullptr) {}
vector(initializer_list<T> il) {
size_t n = il.size();
_start = new T[n];
_finish = _start + n;
_endofstorage = _finish;
copy(il.begin(), il.end(), _start);
}
~vector() {
if (_start) {
delete[] _start;
_start = _finish = _endofstorage = nullptr;
}
}
iterator begin() { return _start; }
iterator end() { return _finish; }
const_iterator begin() const { return _start; }
const_iterator end() const { return _finish; }
reverse_iterator rbegin() { return reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
private:
iterator _start = nullptr;
iterator _finish = nullptr;
iterator _endofstorage = nullptr;
};
}
#pragma once
#include "ReverseIterator.h"
namespace lcz {
template <class T>
class list {
typedef ListNode<T> Node;
public:
typedef ListIterator<T, T&, T*> iterator;
typedef ListIterator<T, const T&, const T*> const_iterator;
typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
typedef ReverseIterator<const_iterator, const T&, const T*> const_reverse_iterator;
list() {
_head = new Node;
_head->_prev = _head;
_head->_next = _head;
_size = 0;
}
list(initializer_list<T> il) : list() {
for (const auto& val : il) {
push_back(val);
}
}
~list() {
clear();
delete _head;
_head = nullptr;
_size = 0;
}
void push_back(const T& val) {
Node* new_node = new Node(val);
Node* tail = _head->_prev;
tail->_next = new_node;
new_node->_prev = tail;
new_node->_next = _head;
_head->_prev = new_node;
_size++;
}
void clear() {
iterator it = begin();
while (it != end()) {
it = erase(it);
}
}
iterator erase(iterator pos) {
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* next = cur->_next;
prev->_next = next;
next->_prev = prev;
delete cur;
_size--;
return iterator(next);
}
iterator begin() { return iterator(_head->_next); }
iterator end() { return iterator(_head); }
const_iterator begin() const { return const_iterator(_head->_next); }
const_iterator end() const { return const_iterator(_head); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
private:
Node* _head = nullptr;
size_t _size = 0;
};
}
#include "list.h"
#include "vector.h"
int main() {
cout << "list 反向遍历:";
lcz::list<int> lt = {1, 2, 3, 4};
lcz::list<int>::reverse_iterator rit = lt.rbegin();
while (rit != lt.rend()) {
cout << *rit << " ";
++rit;
}
cout << endl;
cout << "vector 反向遍历:";
lcz::vector<int> v = {1, 2, 3, 4};
lcz::vector<int>::reverse_iterator vit = v.rbegin();
while (vit != v.rend()) {
cout << *vit << " ";
++vit;
}
cout << endl;
return 0;
}
3. 逆波兰表达式介绍 (也叫后缀表达式)
我们日常写的计算表达式都是中缀表达式,也就是运算符在中间,运算数在两边,但是直接读取无法马上进行运算因为一个计算表达式还涉及运算符优先级问题。如:1-2*(3-4)+5 中遇到 - 和 * 都无法运算,因为后面还有括号优先级更高。所以其中一种实现思路是把中缀表达式转换为后缀表达式,也就是说分析计算表达式的优先级,将运算符放到前面,运算符放到运算数的后面,然后我们依次读取后缀表达式,遇到运算符就可以进行运算了。后缀表达式也就做 逆波兰表达式(Reverse Polish Notation, RPN),这种表示法由 波兰逻辑学家 J·卢卡西维兹 于 1929 年提出,后来被广泛应用于计算机科学中。
3.1 后缀表达式进行运算
后缀表达式因为已经确定好优先级,运算符方式非常简单,就是遇到运算符时,取前面的两个运算符进行运算,因为经过中缀转后缀优先级已经确定好了。建立一个栈存储运算数,读取后缀表达式,遇到运算数入栈,遇到运算符,出栈顶的两个数据进行运算,运算后将结果作为一个运算数入栈继续参与下一次的运算。读取表达式结束后,最后栈里面的值就是运算结果。
3.2 逆波兰表达式求值
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> st;
for (auto str : tokens) {
if (str == "+" || str == "-" || str == "*" || str == "/") {
int right = st.top(); st.pop();
int left = st.top(); st.pop();
switch (str[0]) {
case '+': st.push(left + right); break;
case '-': st.push(left - right); break;
case '*': st.push(left * right); break;
case '/': st.push(left / right); break;
default: break;
}
} else {
st.push(stoi(str));
}
}
return st.top();
}
};
3.3 中缀表达式转后缀表达式 (含代码实现)
1️⃣ 依次读取计算表达式中的值,遇到运算数直接输出。
2️⃣ 建立一个栈存储运算符,利用栈后进新出性质,遇到后面运算符,出栈里面存的前面运算符进行比较,确定优先级。
3️⃣ 遇到运算符,如果栈为空或者栈不为空且当前运算符比栈顶运算符优先级高,则当前运算符入栈。因为如果栈里面存储的是前一个运算符,当前运算符比前一个优先级高,说明前一个不能运算,当前运算符也不能运算,因为后面可能还有更高优先级的运算符。
4️⃣ 遇到运算符,如果栈不为为空且当前运算符比栈顶运算符优先级低或相等,说明栈顶的运算符可以运算了,则输出栈顶运算符,当前运算符继续走前面遇到运算符的逻辑。
5️⃣ 如果遇到 (),则把括号的计算表达式当成一个子表达式,跟上思路类似,进行递归处理子表达式,处理后转换出的后缀表达式加在前面表达式的后面即可。
6️⃣ 计算表达式或者 () 中子表达式结束值,输出栈中所有运算符。
#include <iostream>
#include <stack>
#include <vector>
#include <string>
#include <cctype>
#include <cassert>
using namespace std;
class Solution {
public:
int operatorPrecedence(char ch) {
static const pair<char, int> opPD[] = {{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};
int n = sizeof(opPD) / sizeof(opPD[0]);
for (int i = 0; i < n; ++i) {
if (opPD[i].first == ch) {
return opPD[i].second;
}
}
assert(false && "非法运算符");
return -1;
}
void toRPN(const string& s, size_t& i, vector<string>& rpn, stack<char>& opStack) {
while (i < s.size()) {
if (isdigit(s[i])) {
string num;
while (i < s.size() && isdigit(s[i])) {
num += s[i];
++i;
}
rpn.push_back(num);
} else {
if (s[i] == '(') {
opStack.push(s[i]);
++i;
toRPN(s, i, rpn, opStack);
} else if (s[i] == ')') {
++i;
while (!opStack.empty() && opStack.top() != '(') {
rpn.push_back(string(1, opStack.top()));
opStack.pop();
}
if (!opStack.empty()) {
opStack.pop();
}
return;
} else {
while (!opStack.empty() && opStack.top() != '(' && operatorPrecedence(s[i]) <= operatorPrecedence(opStack.top())) {
rpn.push_back(string(1, opStack.top()));
opStack.pop();
}
opStack.push(s[i]);
++i;
}
}
}
}
vector<string> convertToRPN(const string& s) {
vector<string> rpn;
stack<char> opStack;
size_t i = 0;
toRPN(s, i, rpn, opStack);
while (!opStack.empty()) {
rpn.push_back(string(1, opStack.top()));
opStack.pop();
}
return rpn;
}
int evalRPN(const vector<string>& rpn) {
stack<int> st;
for (const string& token : rpn) {
if (isdigit(token[0]) || (token.size() > 1 && token[0] == '-' && isdigit(token[1]))) {
st.push(stoi(token));
} else {
int b = st.top(); st.pop();
int a = st.top(); st.pop();
int res = 0;
if (token == "+") res = a + b;
else if (token == "-") res = a - b;
else if (token == "*") res = a * b;
else if (token == "/") res = a / b;
st.push(res);
}
}
return st.top();
}
};
int main() {
Solution sol;
string str1 = "1+2-3";
vector<string> rpn1 = sol.convertToRPN(str1);
cout << "中缀表达式:" << str1 << endl;
cout << "逆波兰表达式:";
for (const auto& e : rpn1) {
cout << e << " ";
}
cout << endl;
cout << "计算结果:" << sol.evalRPN(rpn1) << endl;
cout << "------------------------" << endl;
string str2 = "1+2-(3*4+5)-7";
vector<string> rpn2 = sol.convertToRPN(str2);
cout << "中缀表达式:" << str2 << endl;
cout << "逆波兰表达式:";
for (const auto& e : rpn2) {
cout << e << " ";
}
cout << endl;
cout << "计算结果:" << sol.evalRPN(rpn2) << endl;
return 0;
}
4. 基本计算器的实现
有了上面两个部分计算器 OJ 的大部分问题就解决了,但是这里还有一些问题需要处理。因为 OJ 中给的中缀表达式是字符串,字符串中包含空格,需要去掉空格。其次就是负数和减号,要进行区分,将所有的负数-x 转换为 0-x。
class Solution {
public:
int operatorPrecedence(char ch) {
struct opPD {
char _op;
int _pd;
};
static opPD arr[] = {{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};
for (auto& e : arr) {
if (e._op == ch) {
return e._pd;
}
}
assert(false);
return -1;
}
void toRPN(const string& s, size_t& i, vector<string>& v) {
stack<char> st;
while (i < s.size()) {
if (isdigit(s[i])) {
string num;
while (i < s.size() && isdigit(s[i])) {
num += s[i];
++i;
}
v.push_back(num);
} else {
if (s[i] == '(') {
++i;
toRPN(s, i, v);
} else if (s[i] == ')') {
++i;
while (!st.empty()) {
v.push_back(string(1, st.top()));
st.pop();
}
return;
} else {
if (st.empty() || operatorPrecedence(s[i]) > operatorPrecedence(st.top())) {
st.push(s[i]);
++i;
} else {
v.push_back(string(1, st.top()));
st.pop();
}
}
}
}
while (!st.empty()) {
v.push_back(string(1, st.top()));
st.pop();
}
}
long long evalRPN(const vector<string>& tokens) {
stack<long long> s;
for (size_t i = 0; i < tokens.size(); ++i) {
const string& str = tokens[i];
if (!("+" == str || "-" == str || "*" == str || "/" == str)) {
s.push(stoll(str));
} else {
long long right = s.top(); s.pop();
long long left = s.top(); s.pop();
switch (str[0]) {
case '+': s.push(left + right); break;
case '-': s.push(left - right); break;
case '*': s.push(left * right); break;
case '/': s.push(left / right); break;
}
}
}
return s.top();
}
int calculate(string s) {
std::string news;
news.reserve(s.size());
for (auto ch : s) {
if (ch != ' ') news += ch;
}
s.swap(news);
news.clear();
for (size_t i = 0; i < s.size(); ++i) {
if (s[i] == '-' && (i == 0 || (!isdigit(s[i - 1]) && s[i - 1] != ')'))) {
news += "0-";
} else {
news += s[i];
}
}
size_t i = 0;
vector<string> v;
toRPN(news, i, v);
return evalRPN(v);
}
};
解题思路
1️⃣ 表达式预处理
去除空格:首先去除表达式中的所有空格,简化后续处理逻辑。
负数特殊处理:对于出现在表达式开头或左括号后的负号,需要特殊处理。例如,将 "-x" 转换为 "0-x",但为了避免溢出,我们直接将整个负数作为一个完整的数字解析 (如 "-2147483648" 作为一个整体)。
2️⃣ 中缀表达式转后缀表达式 (逆波兰表达式)
使用递归下降法:由于括号会改变运算顺序,我们使用递归的方式处理括号内的子表达式。具体地,遇到左括号时递归处理,直到遇到右括号返回。
运算符优先级:设置加减为 1 级,乘除为 2 级。在转换过程中,如果当前运算符优先级高于栈顶运算符,则入栈;否则将栈顶运算符弹出并加入后缀表达式,直到栈空或遇到更低优先级的运算符。
数字直接输出:遇到数字时,将连续的数字字符拼接成一个完整的数字字符串,直接加入后缀表达式。
3️⃣ 后缀表达式求值
使用栈模拟:遍历后缀表达式,遇到数字则压栈,遇到运算符则弹出栈顶两个数字进行运算,并将结果压栈。
处理大数:由于可能涉及边界值 (如 -2147483648),使用 long long 类型进行计算,避免溢出。最后将结果转换为 int 返回。