ノードが-1または頂点の名前である負でない整数のいずれかを格納するツリーがあります。各頂点は、ツリー内で最大 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 倍) ことです。参考までに、Cygwin で -O3 オプションを指定して g++ を使用しています。
アップデート:
次のコード (バージョン 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のオーバーヘッドが私を悩ませていたので、満足しています。