Тривиальное рекурсивное решение:
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;
}
Требуется ли вам более эффективное или более элегантное решение, естественно, зависит от размера ваших деревьев и от того, как часто вы собираетесь использовать эту процедуру. Вспомните, что сказал Хоар: «преждевременная оптимизация - корень всего зла».