些細な再帰的な解決策:
int count() {
Tree l = getLeftTree();
Tree r = getRightTree();
return 1 + (l != null ? l.count() : 0) + (r != null ? r.count() : 0);
}
それほど自明ではない非再帰的なもの:
int count() {
Stack<Tree> s = new Stack<Tree>();
s.push(this);
int cnt = 0;
while (!s.empty()) {
Tree t = s.pop();
cnt++;
Tree ch = getLeftTree();
if (ch != null) s.push(ch);
ch = getRightTree();
if (ch != null) s.push(ch);
}
return cnt;
}
後者は、再帰をスタックと反復に置き換えるため、おそらくメモリ効率がわずかに高くなります。また、おそらくより高速ですが、測定なしで判断するのは困難です。主な違いは、再帰的なソリューションではスタックを使用するのに対し、非再帰的なソリューションではヒープを使用してノードを格納することです。
編集:これは、スタックの使用量が少ない反復ソリューションのバリアントです。
int count() {
Tree t = this;
Stack<Tree> s = new Stack<Tree>();
int cnt = 0;
do {
cnt++;
Tree l = t.getLeftTree();
Tree r = t.getRightTree();
if (l != null) {
t = l;
if (r != null) s.push(r);
} else if (r != null) {
t = r;
} else {
t = s.empty() ? null : s.pop();
}
} while (t != null);
return cnt;
}
より効率的なソリューションが必要か、より洗練されたソリューションが必要かは、当然、ツリーのサイズと、このルーチンを使用する頻度によって異なります。Hoare が言ったことを思い出してください。「時期尚早の最適化は諸悪の根源です。」