El equilibrio es una propiedad verdaderamente sutil; cree que sabe lo que es, pero es muy fácil equivocarse. En particular, incluso la (buena) respuesta de Eric Lippert es incorrecta. Eso es porque la noción de altura no es suficiente. Necesitas tener el concepto de alturas mínimas y máximas de un árbol (donde la altura mínima es el menor número de pasos desde la raíz hasta una hoja, y el máximo es ... bueno, te haces una idea). Dado eso, podemos definir el equilibrio como:
Un árbol donde la altura máxima de cualquier rama no es más de uno más que la altura mínima de cualquier rama.
(En realidad, esto implica que las ramas están equilibradas; puede elegir la misma rama tanto para el máximo como para el mínimo).
Todo lo que necesita hacer para verificar esta propiedad es un simple recorrido de árbol que realiza un seguimiento de la profundidad actual. La primera vez que retrocede, eso le da una profundidad de referencia. Cada vez que retrocede, compara la nueva profundidad con la línea de base
- si es igual a la línea de base, entonces continúe
- si es más de uno diferente, el árbol no está equilibrado
- si es único, ahora conoce el rango para el equilibrio, y todas las profundidades posteriores (cuando esté a punto de retroceder) deben ser el primer o el segundo valor.
En codigo:
class Tree {
Tree left, right;
static interface Observer {
public void before();
public void after();
public boolean end();
}
static boolean traverse(Tree t, Observer o) {
if (t == null) {
return o.end();
} else {
o.before();
try {
if (traverse(left, o))
return traverse(right, o);
return false;
} finally {
o.after();
}
}
}
boolean balanced() {
final Integer[] heights = new Integer[2];
return traverse(this, new Observer() {
int h;
public void before() { h++; }
public void after() { h--; }
public boolean end() {
if (heights[0] == null) {
heights[0] = h;
} else if (Math.abs(heights[0] - h) > 1) {
return false;
} else if (heights[0] != h) {
if (heights[1] == null) {
heights[1] = h;
} else if (heights[1] != h) {
return false;
}
}
return true;
}
});
}
}
Supongo que podrías hacer esto sin usar el patrón Observer, pero me resulta más fácil razonar de esta manera.
[EDITAR]: Por qué no puedes simplemente tomar la altura de cada lado. Considere este árbol:
/\
/ \
/ \
/ \_____
/\ / \_
/ \ / / \
/\ C /\ / \
/ \ / \ /\ /\
A B D E F G H J
OK, un desordenado poco, pero cada lado de la raíz es equilibrado: C
es la profundidad 2, A
, B
, D
, E
son la profundidad de 3, y F
, G
, H
, J
son la profundidad 4. La altura de la rama izquierda es 2 (recuerde la altura disminuye a medida que atraviesan la rama), la altura de la rama derecha es 3. Sin embargo, el árbol en general no está equilibrado ya que hay una diferencia de altura de 2 entre C
y F
. Necesita una especificación minimax (aunque el algoritmo real puede ser menos complejo, ya que solo debería haber dos alturas permitidas).