I have an complex algorithm which uses really deep recursion. Because there is stack overflow with some specific data I have tried to rewrite it without recursion (using external stack on the heap). So I have two modifications of the same algorithm. Then I have performed some tests and I have found out that recursive implementation is much time faster than another one.
Can someone explain it to me, please? It is part of my final university project to discuss these results (why is one implementation highly faster than another one). I think that it is because of different caching of stack and heap but I am not sure.
Thanks a lot!
EDIT
OK, there is a code. The algorithm is written in C++ and solves tree isomorphism problem. Both implementations are same except one method which compares two nodes. The comparison is defined recursively - one node is lesser than another if one of it's children is lesser than corresponding child of another node.
Recursive version
char compareTo( const IMisraNode * nodeA, const IMisraNode * nodeB ) const {
// comparison of same number of children
int min = std::min( nodeA->getDegree( ), nodeB->getDegree( ) );
for ( int i = 0; i < min; ++i ) {
char res = c开发者_JS百科ompareTo( nodeA->getChild( i ), nodeB->getChild( i ) );
if ( res < 0 ) return -1;
if ( res > 0 ) return 1;
}
if ( nodeA->getDegree( ) == nodeB->getDegree( ) ) return 0; // same number of children
else if ( nodeA->getDegree( ) == min ) return -1;
else return 1;
}
Nonrecursive implementation
struct Comparison {
const IMisraNode * nodeA;
const IMisraNode * nodeB;
int i;
int min; // minimum of count of children
Comparison( const IMisraNode * nodeA, const IMisraNode * nodeB ) :
nodeA( nodeA ), nodeB( nodeB ),
i( 0 ), min( std::min( nodeA->getDegree( ), nodeB->getDegree( ) ) ) { }
} ;
char compareTo( const IMisraNode * nodeA, const IMisraNode * nodeB ) const {
Comparison * cmp = new Comparison( nodeA, nodeB );
// stack on the heap
std::stack<Comparison * > stack;
stack.push( cmp );
char result = 0; // result, the equality is assumed
while ( !result && !stack.empty( ) ) { // while they are not same and there are nodes left
cmp = stack.top( );
// comparison of same children
if ( cmp->i < cmp->min ) {
// compare these children
stack.push( new Comparison( cmp->nodeA->getChild( cmp->i ), cmp->nodeB->getChild( cmp->i ) ) );
++cmp->i; // next node
continue; // continue in comparing on next level
}
if ( cmp->nodeA->getDegree( ) != cmp->nodeB->getDegree( ) ) { // count of children is not same
if ( cmp->nodeA->getDegree( ) == cmp->min ) result = -1; // node A has lesser count of children
else result = 1;
}
delete cmp;
stack.pop( );
}
while ( !stack.empty( ) ) { // clean stack
delete stack.top( );
stack.pop( );
}
return result;
}
Your non-recursive code does dynamic memory allocation (explicitly with new, and implicitly by your use of std::stack), while the recursive one does not. Dynamic memory allocation is an extremely expensive operation.
To speed things up, try storing values, not pointers:
stack <Comparison> astack;
then code like:
astack.push( Comparison( cmp->nodeA->getChild( cmp->i ), cmp->nodeB->getChild( cmp->i ) ) );
Comparison cp = astack.top();
This doesn't answer your speed-comparison question, but rather suggests ways to increase stack size for your recursive solution.
You can increase the stack size (default: 1MB) under VC++: search "stacksize" in Visual Studio help.
And you can do the same under gcc. There's an SO discussion on that very question.
精彩评论