У меня есть дерево, чьи узлы хранят либо -1, либо неотрицательное целое число, которое является именем вершины. Каждая вершина появляется не более одного раза в дереве. Следующая функция является узким местом в моем коде:
Версия A:
void node_vertex_members(node *A, vector<int> *vertexList){
if(A->contents != -1){
vertexList->push_back(A->contents);
}
else{
for(int i=0;i<A->children.size();i++){
node_vertex_members(A->children[i],vertexList);
}
}
}
Версия B:
void node_vertex_members(node *A, vector<int> *vertexList){
stack<node*> q;
q.push(A);
while(!q.empty()){
int x = q.top()->contents;
if(x != -1){
vertexList->push_back(x);
q.pop();
}
else{
node *temp = q.top();
q.pop();
for(int i=temp->children.size()-1; i>=0; --i){
q.push(temp->children[i]);
}
}
}
}
По какой-то причине версия B занимает значительно больше времени, чем версия A, чего я не ожидал. Что может сделать компилятор настолько умнее моего кода? Иными словами, что я делаю так неэффективно? Также меня озадачивает то, что если я попробую что-нибудь вроде проверки в версии B, то ли содержимое для детей -1, прежде чем положить их в стек, он резко замедляется (почти 3 раза). Для справки, я использую g++ в Cygwin с опцией -O3.
Update:
Мне удалось сопоставить рекурсивную версию, используя следующий код (версия C):
node *node_list[65536];
void node_vertex_members(node *A, vector<int> *vertex_list){
int top = 0;
node_list[top] = A;
while(top >= 0){
int x = node_list[top]->contents;
if(x != -1){
vertex_list->push_back(x);
--top;
}
else{
node* temp = node_list[top];
--top;
for(int i=temp->children.size()-1; i>=0; --i){
++top;
node_list[top] = temp->children[i];
}
}
}
}
Очевидными минусами являются длина кода и магическое число (и связанный с ним жесткий предел). И, как я сказал, это соответствует только производительности версии A. Я, конечно, буду придерживаться рекурсивной версии, но теперь я доволен тем, что это было главным образом из-за того, что я был в STL, кусая меня.