L'équilibre est une propriété vraiment subtile; vous pensez savoir ce que c'est, mais il est si facile de se tromper. En particulier, même la (bonne) réponse d'Eric Lippert est erronée. C'est parce que la notion de hauteur ne suffit pas. Vous devez avoir le concept des hauteurs minimales et maximales d'un arbre (où la hauteur minimale est le plus petit nombre de marches entre la racine et une feuille, et le maximum est ... eh bien, vous obtenez l'image). Compte tenu de cela, nous pouvons définir l'équilibre comme étant:
Un arbre dont la hauteur maximale d'une branche ne dépasse pas un de plus que la hauteur minimale d'une branche.
(Cela implique en fait que les branches sont elles-mêmes équilibrées; vous pouvez choisir la même branche pour le maximum et le minimum.)
Tout ce que vous devez faire pour vérifier cette propriété est une simple traversée d'arbre en gardant une trace de la profondeur actuelle. La première fois que vous revenez en arrière, cela vous donne une profondeur de référence. Chaque fois que vous revenez en arrière, vous comparez la nouvelle profondeur à la ligne de base
- si c'est égal à la ligne de base, alors vous continuez
- s'il y en a plus d'un différent, l'arbre n'est pas équilibré
- s'il s'agit d'un seul, vous connaissez maintenant la plage d'équilibre et toutes les profondeurs suivantes (lorsque vous êtes sur le point de revenir en arrière) doivent être la première ou la deuxième valeur.
Dans du code:
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;
}
});
}
}
Je suppose que vous pouvez le faire sans utiliser le modèle Observer, mais je trouve plus facile de raisonner de cette façon.
[EDIT]: Pourquoi vous ne pouvez pas simplement prendre la hauteur de chaque côté. Considérez cet arbre:
/\
/ \
/ \
/ \_____
/\ / \_
/ \ / / \
/\ C /\ / \
/ \ / \ /\ /\
A B D E F G H J
OK, un désordre de peu, mais chaque côté de la racine est équilibrée: C
est la profondeur 2, A
, B
, D
, E
sont la profondeur 3, et F
, G
, H
, J
sont la profondeur 4. La hauteur de la branche gauche est 2 (souvenez - vous de la hauteur diminue à mesure que vous traversez la branche), la hauteur de la branche droite est 3. Pourtant, l'arbre global n'est pas équilibré car il y a une différence de hauteur de 2 entre C
et F
. Vous avez besoin d'une spécification minimax (bien que l'algorithme réel puisse être moins complexe car il ne devrait y avoir que deux hauteurs autorisées).