私は C# で四分木を実装しましたが、逆のように見えるにもかかわらず、反復よりも再帰の方が優れているように見えるという奇妙な出来事に遭遇しました。
私のノードは次のようになります。
class QuadNode
{
private QuadNode topLeft;
private QuadNode topRight;
private QuadNode bottomRight;
private QuadNode bottomLeft;
// other fields...
}
ツリーをトラバースするために、ルート ノードで呼び出す次の再帰メソッドを使用しました。
Traverse()
{
// visit 'this'
if (topLeft != null)
topLeft.Traverse();
if (topRight != null)
topRight.Traverse();
if (bottomRight != null)
bottomRight.Traverse();
if (bottomLeft != null)
bottomLeft.Traverse();
}
ほとんど興味がなく、ツリーをトラバースするための反復メソッドを作成しようとしました。
各ノードに次のフィールドを追加しましprivate QuadNode next
たnext
。基本的に、ツリーのノードから片方向リストを作成しました。
この時点で、次の方法でツリーをトラバースできます。
Traverse()
{
QuadNode node = this;
while (node != null)
{
// visit node
node = node.next;
}
}
各メソッドのパフォーマンスをテストした後、反復バージョンが再帰バージョンよりも一貫して著しく遅いことを知って非常に驚きました. 巨大なツリーと小さなツリーの両方でこれをテストしましたが、再帰的な方法は常に高速です。(Stopwatch
ベンチマークには を使用しました)
両方の方法がツリー全体を正常にトラバースし、反復バージョンは計画どおりに各ノードに 1 回だけアクセスすることを確認したため、それらの間のリンクに問題はありません。
反復バージョンの方がパフォーマンスが優れていることは明らかです...これの原因は何でしょうか? 再帰バージョンの方が速い理由について、明らかな理由を見落としているのでしょうか?
私は Visual Studio 2012 を使用しており、リリースの下でコンパイルされ、任意の CPU (32 ビットのチェックなしを優先) を使用しています。
編集:
新しいプロジェクトを開き、結果を確認する簡単なテストを作成しました。
完全なコードは次のとおりです: http://pastebin.com/SwAsTMjQ
コードはコメントされていませんが、自己文書化されていると思います。