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 fausse. C'est parce que la notion de hauteur n'est pas suffisant. Vous devez avoir le concept de hauteur minimale et maximale d'un arbre (où la hauteur minimale est le plus petit nombre de pas de la racine à une feuille, et le maximum est... eh bien, vous voyez le tableau). Cela étant, nous pouvons définir l'équilibre comme suit :
Un arbre dont la hauteur maximale de toute branche ne dépasse pas un plus que la hauteur minimale de toute 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 de l'arbre en gardant la trace de la profondeur actuelle. La première fois que vous revenez en arrière, cela vous donne une profondeur de base. Ensuite, à chaque fois que vous revenez en arrière, vous comparez la nouvelle profondeur à la profondeur de base.
- s'il est égal à la ligne de base, alors vous continuez simplement
- si c'est plus d'un différent, l'arbre n'est pas équilibré
- s'il s'agit d'une valeur unique, alors 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 soit la première, soit la deuxième valeur.
En 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 pourriez le faire sans utiliser le modèle Observer, mais je trouve que c'est 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 peu désordonné, mais chaque côté de la Racine est équilibré : C
est la profondeur 2, A
, B
, D
, E
sont à la profondeur 3, et F
, G
, H
, J
sont de profondeur 4. La hauteur de la branche gauche est de 2 (rappelez-vous que la hauteur diminue à mesure que vous traversez la branche), la hauteur de la branche droite est de 3. Pourtant, l'arbre global est de no équilibré car il y a une différence de hauteur de 2 entre C
y 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).
0 votes
Si vous souhaitez voir l'arbre binaire ascii de Donal Fellows avec un graphique : i.imgur.com/97C27Ek.png
1 votes
Bonne réponse, elle m'a aidé à entrer aux États-Unis. (blagues)