#c
#c
Вопрос:
Ниже приведен мой простой исходный код программы, и он находит (вложенную) пару круглых скобок и повторяет строку.
2(R) -> RR
#include <iostream>
#include <string>
#include <stack>
using namespace std;
string repeated(string str, int n){
string repeat;
for(int _=0; _<n; _ )
repeat.append(str);
return repeat;
}
string solution(string rgb, int recurdepth) {
stack<int> s;
for(int i=0; i<rgb.size(); i ){
if(rgb[i]=='(') {
s.emplace(i);
}
else if(rgb[i]==')') {
int startp = s.top();
char command = rgb[startp-1];
string childstr = rgb.substr(startp 1, i-(startp 1));
string tmp2;
tmp2 = repeated(childstr, (int) command - '0');
rgb.erase(startp-1, i 1-(startp-1));
rgb.insert(startp-1, tmp2);
// change the string and start from first
return solution(rgb, recurdepth 1);
}
}
// if there are no parenthesis, just return
return rgb;
}
int main(int, char**) {
string in1;
for(int i=0; i<5000; i ) in1.append("2(R)");
cout<< in1.size() << endl;
string answer = solution(in1, 1);
cout << answer.size() << endl;
cout << "answer: " << answer << endl;
}
Я столкнулся с этой ошибкой переполнения стека в MSVC, но не возникло в WSL2 ubuntu 20.04 clang-10.
Я тестировал в Visual Studio 2019.
Unhandled exception at 0x00007FFFF99FE798 (ntdll.dll) in ConsoleApplication1.exe: 0xC00000FD: Stack overflow (parameters: 0x0000000000000001, 0x000000B0F6003FD8).
Что в этом плохого? Я отлаживаю это с помощью VS, но я не знаю, что не так.
Комментарии:
1. Рекурсия может сделать это с вами. Возможно, вам придется найти нерекурсивное решение или быть намного хитрее с тем, как вы распределяете хранилище.
2. Linux по умолчанию имеет стек размером 8 МБ на процесс, в то время как Windows имеет только один стек размером 1 МБ. Это, вероятно, объяснило бы разницу в поведении.
3. Поскольку я знаю, что, хотя строковая переменная объявлена в стеке, она выделяется в куче. Связана ли эта ошибка с этим?
4. Глубина рекурсии ограничена. Строка будет содержать около 24 байт на рекурсию
5. Рекурсия. Вызовы функций почти во всех системах используют стек для передачи данных о вызове, а также для локальных переменных. Глубокая рекурсия исчерпает стек.
Ответ №1:
Я решил свою проблему, изменив свой код рекурсии на код итерации.
#include <iostream>
#include <string>
#include <stack>
using namespace std;
string repeated(string str, int n) {
string repeat;
for (int _ = 0; _ < n; _ )
repeat.append(str);
return repeat;
}
string solution(string rgb) {
bool isthereparen = true;
stack<int> s;
while (isthereparen)
{
for (int i = 0; i < rgb.size(); i ) {
if (rgb[i] == '(') {
s.emplace(i);
}
else if (rgb[i] == ')') {
isthereparen = false;
int startp = s.top();
char command = rgb[startp - 1];
string childstr = rgb.substr(startp 1, i - (startp 1));
string tmp2;
tmp2 = repeated(childstr, (int)command - '0');
rgb.erase(startp - 1, i 1 - (startp - 1));
rgb.insert(startp - 1, tmp2);
break;
}
}
if (isthereparen == false) {
isthereparen = true;
}
else {
isthereparen = false;
}
}
return rgb;
}
int main(int, char**) {
string in1;
for (int i = 0; i < 10000; i ) in1.append("2(R)");
cout << in1.size() << endl;
string answer = solution(in1);
cout << answer.size() << endl;
cout << "answer: " << answer << endl;
}
Да, я знаю, что это не лучший итерационный код, и я предпочитаю рекурсию итерации, но это работает.