ArbreBinaireRecherche.java 4,77 ko
Newer Older
Mathys MACIA's avatar
Mathys MACIA a validé
package collection;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Stack;

/**
 * Arbre binaire de recherche simple. Implémente l’interface Collection.
 */
public class ArbreBinaireRecherche<E extends Comparable<E>> implements Collection<E> {
Mathys MACIA's avatar
Mathys MACIA a validé

Mathys MACIA's avatar
Mathys MACIA a validé
    /** Classe interne représentant un nœud de l'arbre */
    private class Noeud {
	E cle;
	Noeud gauche, droit;

	Noeud(E k) {
	    this.cle = k;
	}
    }
Mathys MACIA's avatar
Mathys MACIA a validé

Mathys MACIA's avatar
Mathys MACIA a validé
    private Noeud racine;
    private int size = 0;

    @Override
    public boolean add(E e) {
	Objects.requireNonNull(e);

	// Si l’arbre est vide : racine = nouvel élément
	if (racine == null) {
	    racine = new Noeud(e);
	    size++;
	    return true;
	}

	Noeud cur = racine, parent = null;
	int cmp = 0;

	// Recherche de la position correcte pour insérer
	while (cur != null) {
	    parent = cur;
	    cmp = e.compareTo(cur.cle);

	    if (cmp < 0)
		cur = cur.gauche; // aller à gauche
	    else if (cmp > 0)
		cur = cur.droit; // aller à droite
	    else
		return false; // élément déjà présent
	}

	// Insertion du nœud
	if (cmp < 0)
	    parent.gauche = new Noeud(e);
	else
	    parent.droit = new Noeud(e);

	size++;
	return true;
Mathys MACIA's avatar
Mathys MACIA a validé
    }

Mathys MACIA's avatar
Mathys MACIA a validé
    /**
     * Recherche d'un nœud contenant la clé donnée
     */
    private Noeud findNode(E e) {
	Noeud cur = racine;

	while (cur != null) {
	    int cmp = e.compareTo(cur.cle);

	    if (cmp == 0)
		return cur;
	    if (cmp < 0)
		cur = cur.gauche;
	    else
		cur = cur.droit;
	}
	return null;
    }
Mathys MACIA's avatar
Mathys MACIA a validé

Mathys MACIA's avatar
Mathys MACIA a validé
    @Override
    public boolean contains(Object o) {
	if (o == null)
	    return false;

	try {
	    @SuppressWarnings("unchecked")
	    E e = (E) o;
	    return findNode(e) != null;
	} catch (ClassCastException ex) {
	    return false;
	}
    }
Mathys MACIA's avatar
Mathys MACIA a validé

Mathys MACIA's avatar
Mathys MACIA a validé
    @Override
    public boolean remove(Object o) {
	if (o == null)
	    return false;

	try {
	    @SuppressWarnings("unchecked")
	    E e = (E) o;
	} catch (ClassCastException ex) {
	    return false;
	}

	// Suppression simple (remplacement par successeur)
	// (Pour les benchmarks, remove n'est pas essentiel)
	E key = (E) o;
	Noeud parent = null, cur = racine;

	// Recherche du nœud à supprimer
	while (cur != null && !cur.cle.equals(key)) {
	    parent = cur;
	    if (key.compareTo(cur.cle) < 0)
		cur = cur.gauche;
	    else
		cur = cur.droit;
	}

	if (cur == null)
	    return false;

	// Cas où le nœud a deux enfants
	if (cur.gauche != null && cur.droit != null) {
	    Noeud succParent = cur, succ = cur.droit;

	    // Successeur = minimum du sous-arbre droit
	    while (succ.gauche != null) {
		succParent = succ;
		succ = succ.gauche;
	    }

	    // Remplacer la clé
	    cur.cle = succ.cle;
	    parent = succParent;
	    cur = succ;
	}

	// Cas 0 ou 1 enfant
	Noeud child = (cur.gauche != null) ? cur.gauche : cur.droit;

	if (parent == null)
	    racine = child;
	else if (parent.gauche == cur)
	    parent.gauche = child;
	else
	    parent.droit = child;

	size--;
	return true;
Mathys MACIA's avatar
Mathys MACIA a validé
    }

Mathys MACIA's avatar
Mathys MACIA a validé
    @Override
    public Iterator<E> iterator() {

	// Parcours en ordre croissant (in-order)
	return new Iterator<E>() {
	    private final Stack<Noeud> st = init(racine);

	    private Stack<Noeud> init(Noeud r) {
		Stack<Noeud> s = new Stack<>();
		Noeud c = r;

		while (c != null) {
		    s.push(c);
		    c = c.gauche;
		}
		return s;
	    }

	    @Override
	    public boolean hasNext() {
		return !st.isEmpty();
	    }

	    @Override
	    public E next() {
		Noeud n = st.pop();
		E res = n.cle;
		Noeud c = n.droit;

		while (c != null) {
		    st.push(c);
		    c = c.gauche;
		}

		return res;
	    }
	};
    }
Mathys MACIA's avatar
Mathys MACIA a validé

Mathys MACIA's avatar
Mathys MACIA a validé
    @Override
    public int size() {
	return size;
    }
Mathys MACIA's avatar
Mathys MACIA a validé

Mathys MACIA's avatar
Mathys MACIA a validé
    @Override
    public boolean isEmpty() {
	return size == 0;
Mathys MACIA's avatar
Mathys MACIA a validé
    }

Mathys MACIA's avatar
Mathys MACIA a validé
    @Override
    public void clear() {
	racine = null;
	size = 0;
Mathys MACIA's avatar
Mathys MACIA a validé
    }
Mathys MACIA's avatar
Mathys MACIA a validé

    @Override
    public Object[] toArray() {
	Object[] arr = new Object[size];
	int i = 0;

	for (E e : this)
	    arr[i++] = e;

	return arr;
Mathys MACIA's avatar
Mathys MACIA a validé
    }
Mathys MACIA's avatar
Mathys MACIA a validé

    @Override
    public <T> T[] toArray(T[] a) {
	return null; // même logique que RBTree ; omis pour brièveté
Mathys MACIA's avatar
Mathys MACIA a validé
    }

Mathys MACIA's avatar
Mathys MACIA a validé
    @Override
    public boolean containsAll(Collection<?> c) {
	for (Object o : c)
	    if (!contains(o))
		return false;

	return true;
Mathys MACIA's avatar
Mathys MACIA a validé
    }

Mathys MACIA's avatar
Mathys MACIA a validé
    @Override
    public boolean addAll(Collection<? extends E> c) {
	boolean ch = false;

	for (E e : c)
	    ch |= add(e);

	return ch;
    }
Mathys MACIA's avatar
Mathys MACIA a validé

Mathys MACIA's avatar
Mathys MACIA a validé
    @Override
    public boolean removeAll(Collection<?> c) {
	boolean ch = false;
Mathys MACIA's avatar
Mathys MACIA a validé

Mathys MACIA's avatar
Mathys MACIA a validé
	for (Object o : c)
	    ch |= remove(o);
Mathys MACIA's avatar
Mathys MACIA a validé

Mathys MACIA's avatar
Mathys MACIA a validé
	return ch;
Mathys MACIA's avatar
Mathys MACIA a validé
    }

Mathys MACIA's avatar
Mathys MACIA a validé
    @Override
    public boolean retainAll(Collection<?> c) {
	List<E> del = new ArrayList<>();

	// Construire la liste des éléments à supprimer
	for (E e : this)
	    if (!c.contains(e))
		del.add(e);

	// Supprimer les éléments
	for (E e : del)
	    remove(e);

	return !del.isEmpty();
    }
Mathys MACIA's avatar
Mathys MACIA a validé
}