#c #recursion #tree #stack-overflow
#c #рекурсия #дерево #переполнение стека
Вопрос:
Я прочитал много похожих статей, прошу прощения, если на этот вопрос уже был дан ответ, но я все еще застрял.
Я кодирую функцию для заполнения дерева, каждый узел которого имеет четыре ветви, в которых будут храниться возможные манипуляции с состояниями «головоломки из восьми плиток», т.е.http://www.8puzzle.com/images/8_puzzle_start_state_a.png
Проблема в том, что я достиг, как я полагаю, переполнения стека из-за сильно рекурсивного характера рассматриваемой проблемы.
Хвостовая рекурсия кажется решением, хотя я не уверен, уместно ли это / возможно или как это реализовать в данном случае. Следующий код:
void Tree::insert(string amp;initialState, const string amp;goalState, tree_node *amp;inNode){
cout<<"insert called"<<endl;
depth ;
cout<<depth<<endl;
string modState;
int zeroPos=0;
if(initialState==goalState){
cout<<"* * * GOAL * * *"<<endl;
getchar();
exit(0);
}
if(inNode==NULL){//is this the first node?
inNode = new tree_node(initialState);
root=inNode;
inNode->parent=NULL;
insert(initialState, goalState, inNode);
}else{
inNode->state = initialState;
for(zeroPos=0;zeroPos<initialState.size();zeroPos ){//where is the empty tile?
if(initialState[zeroPos]=='0'){
break;
}
}
//left
if(zeroPos!=0 amp;amp; zeroPos!=3 amp;amp; zeroPos!=6){//can the empty tile move left?
modState=initialState;
modState[zeroPos]=modState[zeroPos-1];
modState[zeroPos-1]='0';
if(isOriginal(modState, inNode) ){//does this state already exist?
cout <<"left " << modState[0]<<modState[1]<<modState[2]<<endl;
cout <<"left " << modState[3]<<modState[4]<<modState[5]<<endl;
cout <<"left " << modState[6]<<modState[7]<<modState[8]<<endl;
inNode->l = new tree_node(modState);
inNode->l->parent= inNode;
if(inNode->l != NULL){
insert(modState, goalState, inNode->l);
}
}
}
}
}
}
Комментарии:
1. Я не просматривал ваш код, но я был бы удивлен, если вы получаете переполнение стека в 8-головоломке, если ваш алгоритм работает должным образом.
2. Возможно, дерево всех состояний не является наилучшей возможной реализацией?
3. Вероятно, мне следовало упомянуть, что я намеревался запускать различные алгоритмы поиска, находить шаги к целевому состоянию и записывать их эффективность в различных аспектах (время, использование памяти и т.д.).
4. @RemnantXO Почему вы создаете дерево состояний перед запуском алгоритмов поиска?
5. Хм. Есть ли альтернативный способ их запуска? Я не могу придумать, как искать состояния, не упорядочивая их в какой-либо структуре. Возможно, я просто удивительно недалек и упускаю очевидное?
Ответ №1:
Это очень общий ответ, но пытались ли вы явно управлять своим стеком через что-то вроде очереди, выделенной из кучи, или стека? В принципе, не используйте фактические вызовы функций, просто нажимайте и извлекайте что-то из своего собственного стека / очереди. Здесь рассматриваются нерекурсивные алгоритмы обхода графа (поиск как в глубину, так и в ширину).
Ответ №2:
Оптимизируйте свой код, то есть сохраняйте только те узлы, которые вам нужны. Например, сохраняйте только конечные узлы (я имею в виду те, которые вы еще не расширили). И да, вы можете выполнить поиск в дереве во время его построения, написать функцию для измерения расстояния между вашим текущим состоянием и вашим целевым состоянием, это называется эвристическим. Есть также лучший алгоритм, который решает 8puzzle, он называется A *, я предлагаю вам погуглить его.
Комментарии:
1. Но разве узлы, которые динамически распределяются, не хранятся в куче? Я буду внедрять A *, но я сравниваю ряд функций поиска.
2. да, но вы могли бы удалить узлы, которые вы уже расширили, то есть, когда вы добавили все дочерние элементы, удалите сам узел.