diff --git a/ABR_insert.csv b/ABR_insert.csv
index c2f7b2e5cc0a1d316b38f238fee556832496a913..3e13050e69d1d57711ddf3f3b715223daeca61a5 100644
--- a/ABR_insert.csv
+++ b/ABR_insert.csv
@@ -1,3 +1,3 @@
n,1000,2000,5000,10000,20000,50000
-ASCENDANT,1231700,00,4418640,00,30034160,00,116455020,00,474819140,00,3056061360,00
-ALEATOIRE,149580,00,167500,00,356340,00,830320,00,1814660,00,5609920,00
+ASCENDANT,2741266,60,4242239,60,25764592,60,103848038,60,427439882,20,2674167635,60
+ALEATOIRE,296387,40,450203,40,656077,20,1670061,80,3761467,60,11957840,20
diff --git a/ABR_search.csv b/ABR_search.csv
index e12ff3ce2e7f9c39cc581601408dd2085649923a..69f62c11ef53a995557c10ae388cbb295705bbe2 100644
--- a/ABR_search.csv
+++ b/ABR_search.csv
@@ -1,3 +1,3 @@
n,1000,2000,5000,10000,20000,50000
-ASCENDANT,2658220,00,9699160,00,60452520,00,233926280,00,907753720,00,5800536280,00
-ALEATOIRE,128340,00,122680,00,310240,00,577920,00,1311820,00,3409080,00
+ASCENDANT,4158852,60,12248819,80,76968346,20,319434800,40,1309307052,20,8234666725,00
+ALEATOIRE,266154,80,235807,80,574324,40,1102771,40,2151257,40,5866763,00
diff --git a/ARN_insert.csv b/ARN_insert.csv
index afb83d219a47527e8355b50b64508e86a098def9..5ff730214b8dfe382c89f70e4c924a3d079cc449 100644
--- a/ARN_insert.csv
+++ b/ARN_insert.csv
@@ -1,3 +1,3 @@
n,1000,2000,5000,10000,20000,50000
-ASCENDANT,221140,00,242880,00,405760,00,720540,00,761520,00,1803680,00
-ALEATOIRE,153900,00,219500,00,457300,00,938200,00,2106160,00,6222500,00
+ASCENDANT,429293,00,541214,60,1492209,80,1450807,80,1846437,80,4429069,40
+ALEATOIRE,402464,80,359252,00,1019308,20,1808727,00,3546869,20,11937927,00
diff --git a/ARN_search.csv b/ARN_search.csv
index 107032e6f5526cf8a136cb5c961e0817f73d3c5d..5664606bf0d8cbb49d3e4eb151f084fc85430d92 100644
--- a/ARN_search.csv
+++ b/ARN_search.csv
@@ -1,3 +1,3 @@
n,1000,2000,5000,10000,20000,50000
-ASCENDANT,136940,00,128920,00,320120,00,733100,00,1475920,00,4872060,00
-ALEATOIRE,51780,00,101540,00,308340,00,616120,00,1244160,00,3500360,00
+ASCENDANT,353458,80,290777,00,621226,20,1336956,20,2635875,60,9406446,40
+ALEATOIRE,63701,80,132267,60,378176,00,815282,80,1745943,60,5169691,20
diff --git a/pom.xml b/pom.xml
index ab64bfe978840e2955ed21870007ff90ef9cfb24..78300031874a529c20446e595cfa3ac3e5f860ba 100644
--- a/pom.xml
+++ b/pom.xml
@@ -61,13 +61,43 @@
maven-site-plugin
3.21.0
-
+
+ org.jacoco
+ jacoco-maven-plugin
+ 0.8.12
+
+
+ default-prepare-agent
+
+ prepare-agent
+
+
+
+ default-report
+
+ report
+
+
+
+ default-check
+
+ check
+
+
+
+
+
org.apache.maven.plugins
maven-checkstyle-plugin
3.6.0
+
+
+ google_checks.xml
+
+
com.puppycrawl.tools
@@ -102,6 +132,19 @@
maven-javadoc-plugin
3.12.0
-
-
+
+ org.jacoco
+ jacoco-maven-plugin
+ 0.8.12
+
+
+
+
+ report
+
+
+
+
+
+
diff --git a/src/main/java/collection/ArbreBinaireRecherche.java b/src/main/java/collection/ArbreBinaireRecherche.java
index 5945dbfc05acc30c08ea2fcc33f7a2877a40edf2..236911adc269ab17bcb8ac3f177c5b97fa24137f 100644
--- a/src/main/java/collection/ArbreBinaireRecherche.java
+++ b/src/main/java/collection/ArbreBinaireRecherche.java
@@ -12,261 +12,282 @@ import java.util.Stack;
*/
public class ArbreBinaireRecherche> implements Collection {
- /** Classe interne représentant un nœud de l'arbre */
- private class Noeud {
- E cle;
- Noeud gauche, droit;
-
- Noeud(E k) {
- this.cle = k;
- }
+ /** Classe interne représentant un nœud de l'arbre */
+ private class Noeud {
+ E cle;
+ Noeud gauche;
+ Noeud droit;
+
+ Noeud(E k) {
+ this.cle = k;
}
+ }
- 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;
+ private Noeud racine;
+ private int taille = 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);
+ taille++;
+ return true;
+ }
+
+ Noeud actuel = racine;
+ Noeud parent = null;
+ int cmp = 0;
+
+ // Recherche de la position correcte pour insérer
+ while (actuel != null) {
+ parent = actuel;
+ cmp = e.compareTo(actuel.cle);
+
+ if (cmp < 0) {
+ actuel = actuel.gauche; // aller à gauche
+ } else if (cmp > 0) {
+ actuel = actuel.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);
}
- /**
- * 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;
+ taille++;
+ return true;
+ }
+
+ /**
+ * Recherche d'un nœud contenant la clé donnée
+ */
+ private Noeud findNode(E e) {
+ Noeud actuel = racine;
+
+ while (actuel != null) {
+ int cmp = e.compareTo(actuel.cle);
+
+ if (cmp == 0) {
+ return actuel;
+ }
+ if (cmp < 0) {
+ actuel = actuel.gauche;
+ } else {
+ actuel = actuel.droit;
+ }
}
+ return null;
+ }
- @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;
- }
+ @Override
+ public boolean contains(Object o) {
+ if (o == null) {
+ return false;
}
- @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;
+ try {
+ @SuppressWarnings("unchecked")
+ E e = (E) o;
+ return findNode(e) != null;
+ } catch (ClassCastException ex) {
+ return false;
}
+ }
- @Override
- public Iterator iterator() {
-
- // Parcours en ordre croissant (in-order)
- return new Iterator() {
- private final Stack st = init(racine);
-
- private Stack init(Noeud r) {
- Stack 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;
- }
- };
+ @Override
+ public boolean remove(Object o) {
+ if (o == null) {
+ return false;
}
- @Override
- public int size() {
- return size;
+ try {
+ @SuppressWarnings("unchecked")
+ E e = (E) o;
+ } catch (ClassCastException ex) {
+ return false;
}
- @Override
- public boolean isEmpty() {
- return size == 0;
+ // Suppression simple (remplacement par successeur)
+ // (Pour les benchmarks, remove n'est pas essentiel)
+ E key = (E) o;
+ Noeud parent = null;
+ Noeud actuel = racine;
+
+ // Recherche du nœud à supprimer
+ while (actuel != null && !actuel.cle.equals(key)) {
+ parent = actuel;
+ if (key.compareTo(actuel.cle) < 0) {
+ actuel = actuel.gauche;
+ } else {
+ actuel = actuel.droit;
+ }
}
- @Override
- public void clear() {
- racine = null;
- size = 0;
+ if (actuel == null) {
+ return false;
}
- @Override
- public Object[] toArray() {
- Object[] arr = new Object[size];
- int i = 0;
+ // Cas où le nœud a deux enfants
+ if (actuel.gauche != null && actuel.droit != null) {
+ Noeud succParent = actuel;
+ Noeud suivant = actuel.droit;
+
+ // Successeur = minimum du sous-arbre droit
+ while (suivant.gauche != null) {
+ succParent = suivant;
+ suivant = suivant.gauche;
+ }
+
+ // Remplacer la clé
+ actuel.cle = suivant.cle;
+ parent = succParent;
+ actuel = suivant;
+ }
- for (E e : this)
- arr[i++] = e;
+ // Cas 0 ou 1 enfant
+ Noeud child = (actuel.gauche != null) ? actuel.gauche : actuel.droit;
- return arr;
+ if (parent == null) {
+ racine = child;
+ } else if (parent.gauche == actuel) {
+ parent.gauche = child;
+ } else {
+ parent.droit = child;
}
- @Override
- public T[] toArray(T[] a) {
- return null; // même logique que RBTree ; omis pour brièveté
+ taille--;
+ return true;
+ }
+
+ @Override
+ public Iterator iterator() {
+
+ // Parcours en ordre croissant (in-order)
+ return new Iterator() {
+ private final Stack st = init(racine);
+
+ private Stack init(Noeud r) {
+ Stack 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;
+ }
+ };
+ }
+
+ @Override
+ public int size() {
+ return taille;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return taille == 0;
+ }
+
+ @Override
+ public void clear() {
+ racine = null;
+ taille = 0;
+ }
+
+ @Override
+ public Object[] toArray() {
+ Object[] arr = new Object[taille];
+ int i = 0;
+
+ for (E e : this) {
+ arr[i++] = e;
}
- @Override
- public boolean containsAll(Collection> c) {
- for (Object o : c)
- if (!contains(o))
- return false;
+ return arr;
+ }
+
+ @Override
+ public T[] toArray(T[] a) {
+ return null; // même logique que RBTree ; omis pour brièveté
+ }
- return true;
+ @Override
+ public boolean containsAll(Collection> c) {
+ for (Object o : c) {
+ if (!contains(o)) {
+ return false;
+ }
}
- @Override
- public boolean addAll(Collection extends E> c) {
- boolean ch = false;
+ return true;
+ }
- for (E e : c)
- ch |= add(e);
+ @Override
+ public boolean addAll(Collection extends E> c) {
+ boolean ch = false;
- return ch;
+ for (E e : c) {
+ ch |= add(e);
}
- @Override
- public boolean removeAll(Collection> c) {
- boolean ch = false;
+ return ch;
+ }
- for (Object o : c)
- ch |= remove(o);
+ @Override
+ public boolean removeAll(Collection> c) {
+ boolean ch = false;
- return ch;
+ for (Object o : c) {
+ ch |= remove(o);
}
- @Override
- public boolean retainAll(Collection> c) {
- List del = new ArrayList<>();
+ return ch;
+ }
- // Construire la liste des éléments à supprimer
- for (E e : this)
- if (!c.contains(e))
- del.add(e);
+ @Override
+ public boolean retainAll(Collection> c) {
+ List del = new ArrayList<>();
- // Supprimer les éléments
- for (E e : del)
- remove(e);
+ // Construire la liste des éléments à supprimer
+ for (E e : this) {
+ if (!c.contains(e)) {
+ del.add(e);
+ }
+ }
- return !del.isEmpty();
+ // Supprimer les éléments
+ for (E e : del) {
+ remove(e);
}
+
+ return !del.isEmpty();
+ }
}
diff --git a/src/main/java/collection/Benchmark.java b/src/main/java/collection/Benchmark.java
index 40c158cee98d1238aa087f938ae4bcf7a0b9b5a7..ef747c7c7d52f3be0ede4ae5a5d463906b79fc9a 100644
--- a/src/main/java/collection/Benchmark.java
+++ b/src/main/java/collection/Benchmark.java
@@ -11,128 +11,136 @@ import java.util.Random;
public class Benchmark {
- private static final Random RNG = new Random(12345);
+ private static final Random RNG = new Random(12345);
- public static void main(final String[] args) throws Exception {
+ public static void main(final String[] args) throws Exception {
- final int[] N_LIST = { 1000, 2000, 5000, 10000, 20000, 50000 };
- final int REP = 5;
+ final int[] nList = { 1000, 2000, 5000, 10000, 20000, 50000 };
+ final int repetition = 5;
- // --- Create the 4 CSV writers ---
- PrintWriter abrInsert = new PrintWriter(new FileWriter("ABR_insert.csv"));
- PrintWriter abrSearch = new PrintWriter(new FileWriter("ABR_search.csv"));
- PrintWriter arnInsert = new PrintWriter(new FileWriter("ARN_insert.csv"));
- PrintWriter arnSearch = new PrintWriter(new FileWriter("ARN_search.csv"));
+ // --- Creation des 4 CSV avec leur enTete ---
+ PrintWriter abrInsert = new PrintWriter(new FileWriter("ABR_insert.csv"));
+ writeHeader(abrInsert, nList);
- // Header line : n,1000,2000,...
- writeHeader(abrInsert, N_LIST);
- writeHeader(abrSearch, N_LIST);
- writeHeader(arnInsert, N_LIST);
- writeHeader(arnSearch, N_LIST);
+ PrintWriter abrSearch = new PrintWriter(new FileWriter("ABR_search.csv"));
+ writeHeader(abrSearch, nList);
- // Scenarios
- List scenarios = Arrays.asList("ASCENDANT", "ALEATOIRE");
+ PrintWriter arnInsert = new PrintWriter(new FileWriter("ARN_insert.csv"));
+ writeHeader(arnInsert, nList);
- // Process each structure
- for (String structure : Arrays.asList("ABR", "ARN")) {
+ PrintWriter arnSearch = new PrintWriter(new FileWriter("ARN_search.csv"));
+ writeHeader(arnSearch, nList);
- for (String scenario : scenarios) {
+ // Scenarios
+ List scenarios = Arrays.asList("ASCENDANT", "ALEATOIRE");
- // Buffers for one line of insert & search results
- List insertLine = new ArrayList<>();
- List searchLine = new ArrayList<>();
+ // Process each structure
+ for (String structure : Arrays.asList("ABR", "ARN")) {
- for (int n : N_LIST) {
+ for (String scenario : scenarios) {
- long insertSum = 0;
- long searchSum = 0;
+ // Buffers for one line of insert & search results
+ List insertLine = new ArrayList<>();
+ List searchLine = new ArrayList<>();
- for (int r = 0; r < REP; r++) {
+ for (int n : nList) {
- List keys = new ArrayList<>();
- for (int i = 0; i < n; i++)
- keys.add(i);
+ long insertSum = 0;
+ long searchSum = 0;
- if (scenario.equals("ALEATOIRE")) {
- Collections.shuffle(keys, new Random(RNG.nextLong()));
- }
+ for (int r = 0; r < repetition; r++) {
- long[] result = structure.equals("ABR") ? benchmarkABR(keys, n) : benchmarkARN(keys, n);
+ List keys = new ArrayList<>();
+ for (int i = 0; i < n; i++) {
+ keys.add(i);
+ }
- insertSum += result[0];
- searchSum += result[1];
- }
+ if (scenario.equals("ALEATOIRE")) {
+ Collections.shuffle(keys, new Random(RNG.nextLong()));
+ }
- insertLine.add(insertSum / (double) REP);
- searchLine.add(searchSum / (double) REP);
+ long[] result = structure.equals("ABR") ? benchmarkAbr(keys, n) : benchmarkArn(keys, n);
- System.out.printf("Done %s %s n=%d\n", structure, scenario, n);
- }
+ insertSum += result[0];
+ searchSum += result[1];
+ }
- // Write to correct CSV
- if (structure.equals("ABR")) {
- writeScenarioLine(abrInsert, scenario, insertLine);
- writeScenarioLine(abrSearch, scenario, searchLine);
- } else {
- writeScenarioLine(arnInsert, scenario, insertLine);
- writeScenarioLine(arnSearch, scenario, searchLine);
- }
- }
- }
+ insertLine.add(insertSum / (double) repetition);
+ searchLine.add(searchSum / (double) repetition);
- abrInsert.close();
- abrSearch.close();
- arnInsert.close();
- arnSearch.close();
+ System.out.printf("Done %s %s n=%d\n", structure, scenario, n);
+ }
- System.out.println("4 CSV créés au format tableau.");
+ // Write to correct CSV
+ if (structure.equals("ABR")) {
+ writeScenarioLine(abrInsert, scenario, insertLine);
+ writeScenarioLine(abrSearch, scenario, searchLine);
+ } else {
+ writeScenarioLine(arnInsert, scenario, insertLine);
+ writeScenarioLine(arnSearch, scenario, searchLine);
+ }
+ }
}
- // -------------------------------------------------------
- // Helper: header line
- // -------------------------------------------------------
- private static void writeHeader(PrintWriter pw, int[] nList) {
- pw.print("n");
- for (int n : nList)
- pw.print("," + n);
- pw.println();
+ abrInsert.close();
+ abrSearch.close();
+ arnInsert.close();
+ arnSearch.close();
+
+ System.out.println("4 CSV créés au format tableau.");
+ }
+
+ // -------------------------------------------------------
+ // Helper: header line
+ // -------------------------------------------------------
+ private static void writeHeader(PrintWriter pw, int[] nlist) {
+ pw.print("n");
+ for (int n : nlist) {
+ pw.print("," + n);
}
- // -------------------------------------------------------
- // Helper: write one scenario line
- // -------------------------------------------------------
- private static void writeScenarioLine(PrintWriter pw, String scenario, List values) {
- pw.print(scenario);
- for (double v : values)
- pw.printf(",%.2f", v);
- pw.println();
+ pw.println();
+ }
+
+ // -------------------------------------------------------
+ // Helper: write one scenario line
+ // -------------------------------------------------------
+ private static void writeScenarioLine(PrintWriter pw, String scenario, List values) {
+ pw.print(scenario);
+ for (double v : values) {
+ pw.printf(",%.2f", v);
}
- // -------------------------------------------------------
- // Benchmark ABR / ARN
- // -------------------------------------------------------
+ pw.println();
+ }
- private static long[] benchmarkABR(List keys, int n) {
- Collection tree = new ArbreBinaireRecherche<>();
- return runBenchmark(tree, keys, n);
- }
+ // -------------------------------------------------------
+ // Benchmark ABR / ARN
+ // -------------------------------------------------------
- private static long[] benchmarkARN(List keys, int n) {
- Collection tree = new RedBlackTree<>();
- return runBenchmark(tree, keys, n);
- }
+ private static long[] benchmarkAbr(List keys, int n) {
+ Collection tree = new ArbreBinaireRecherche<>();
+ return runBenchmark(tree, keys, n);
+ }
- private static long[] runBenchmark(Collection tree, List keys, int n) {
- long t0 = System.nanoTime();
- for (Integer k : keys)
- tree.add(k);
- long t1 = System.nanoTime();
+ private static long[] benchmarkArn(List keys, int n) {
+ Collection tree = new RedBlackTree<>();
+ return runBenchmark(tree, keys, n);
+ }
- long t2 = System.nanoTime();
- for (int x = 0; x < 2 * n; x++)
- tree.contains(x);
- long t3 = System.nanoTime();
+ private static long[] runBenchmark(Collection tree, List keys, int n) {
+ long t0 = System.nanoTime();
+ for (Integer k : keys) {
+ tree.add(k);
+ }
+ long t1 = System.nanoTime();
- return new long[] { t1 - t0, t3 - t2 };
+ long t2 = System.nanoTime();
+ for (int x = 0; x < 2 * n; x++) {
+ tree.contains(x);
}
+ long t3 = System.nanoTime();
+
+ return new long[] { t1 - t0, t3 - t2 };
+ }
}
diff --git a/src/main/java/collection/RedBlackTree.java b/src/main/java/collection/RedBlackTree.java
index 83047397cf03823988a0a9a4c819a25255eb832e..98c909367683644023e7df9cd54f88e1e6a40fcb 100644
--- a/src/main/java/collection/RedBlackTree.java
+++ b/src/main/java/collection/RedBlackTree.java
@@ -16,497 +16,543 @@ import java.util.Stack;
* contiennent le même nombre de nœuds noirs
*/
public class RedBlackTree> implements Collection {
- private static final boolean RED = true;
- private static final boolean BLACK = false;
-
- /** Classe interne représentant un nœud de l'arbre */
- private class Node {
- E key;
- Node left, right, parent;
- boolean color = RED; // par défaut, un nouveau nœud est rouge
-
- Node(E key, Node parent) {
- this.key = key;
- this.parent = parent;
- }
+ private static final boolean ROUGE = true;
+ private static final boolean NOIR = false;
+
+ /** Classe interne représentant un nœud de l'arbre */
+ private class Noeud {
+ E cle;
+ Noeud gauche;
+ Noeud droit;
+ Noeud parent;
+ boolean color = ROUGE; // par défaut, un nouveau nœud est rouge
+
+ Noeud(E cle, Noeud parent) {
+ this.cle = cle;
+ this.parent = parent;
}
+ }
- private Node root;
- private int size = 0;
+ private Noeud racine;
+ private int taille = 0;
- /** Rotation gauche standard */
- private void rotateLeft(Node x) {
- Node y = x.right;
- x.right = y.left;
+ /** Rotation gauche standard */
+ private void rotateLeft(Noeud x) {
+ Noeud y = x.droit;
+ x.droit = y.gauche;
- if (y.left != null)
- y.left.parent = x;
-
- y.parent = x.parent;
+ if (y.gauche != null) {
+ y.gauche.parent = x;
+ }
- if (x.parent == null)
- root = y;
- else if (x == x.parent.left)
- x.parent.left = y;
- else
- x.parent.right = y;
+ y.parent = x.parent;
- y.left = x;
- x.parent = y;
+ if (x.parent == null) {
+ racine = y;
+ } else if (x == x.parent.gauche) {
+ x.parent.gauche = y;
+ } else {
+ x.parent.droit = y;
}
- /** Rotation droite standard */
- private void rotateRight(Node x) {
- Node y = x.left;
- x.left = y.right;
+ y.gauche = x;
+ x.parent = y;
+ }
- if (y.right != null)
- y.right.parent = x;
+ /** Rotation droite standard */
+ private void rotateRight(Noeud x) {
+ Noeud y = x.gauche;
+ x.gauche = y.droit;
- y.parent = x.parent;
+ if (y.droit != null) {
+ y.droit.parent = x;
+ }
- if (x.parent == null)
- root = y;
- else if (x == x.parent.right)
- x.parent.right = y;
- else
- x.parent.left = y;
+ y.parent = x.parent;
- y.right = x;
- x.parent = y;
+ if (x.parent == null) {
+ racine = y;
+ } else if (x == x.parent.droit) {
+ x.parent.droit = y;
+ } else {
+ x.parent.gauche = y;
}
- /**
- * Correction après insertion. Assure que les propriétés RB sont conservées.
- */
- private void fixAfterInsert(Node z) {
- while (z.parent != null && z.parent.color == RED) {
- if (z.parent == z.parent.parent.left) {
- Node y = z.parent.parent.right; // oncle
-
- if (y != null && y.color == RED) {
- // Cas 1 : parent rouge + oncle rouge -> recolorations
- z.parent.color = BLACK;
- y.color = BLACK;
- z.parent.parent.color = RED;
- z = z.parent.parent;
- } else {
- if (z == z.parent.right) {
- // Cas 2 : triangle -> rotation gauche
- z = z.parent;
- rotateLeft(z);
- }
-
- // Cas 3 : ligne -> rotation droite
- z.parent.color = BLACK;
- z.parent.parent.color = RED;
- rotateRight(z.parent.parent);
- }
- } else {
- // Symétrique : parent est enfant droit
- Node y = z.parent.parent.left;
-
- if (y != null && y.color == RED) {
- z.parent.color = BLACK;
- y.color = BLACK;
- z.parent.parent.color = RED;
- z = z.parent.parent;
- } else {
- if (z == z.parent.left) {
- z = z.parent;
- rotateRight(z);
- }
- z.parent.color = BLACK;
- z.parent.parent.color = RED;
- rotateLeft(z.parent.parent);
- }
- }
- }
-
- root.color = BLACK;
+ y.droit = x;
+ x.parent = y;
+ }
+
+ /**
+ * Correction après insertion. Assure que les propriétés RB sont conservées.
+ */
+ private void fixAfterInsert(Noeud z) {
+ while (z.parent != null && z.parent.color == ROUGE) {
+ if (z.parent == z.parent.parent.gauche) {
+ Noeud y = z.parent.parent.droit; // oncle
+
+ if (y != null && y.color == ROUGE) {
+ // Cas 1 : parent rouge + oncle rouge -> recolorations
+ z.parent.color = NOIR;
+ y.color = NOIR;
+ z.parent.parent.color = ROUGE;
+ z = z.parent.parent;
+ } else {
+ if (z == z.parent.droit) {
+ // Cas 2 : triangle -> rotation gauche
+ z = z.parent;
+ rotateLeft(z);
+ }
+
+ // Cas 3 : ligne -> rotation droite
+ z.parent.color = NOIR;
+ z.parent.parent.color = ROUGE;
+ rotateRight(z.parent.parent);
+ }
+ } else {
+ // Symétrique : parent est enfant droit
+ Noeud y = z.parent.parent.gauche;
+
+ if (y != null && y.color == ROUGE) {
+ z.parent.color = NOIR;
+ y.color = NOIR;
+ z.parent.parent.color = ROUGE;
+ z = z.parent.parent;
+ } else {
+ if (z == z.parent.gauche) {
+ z = z.parent;
+ rotateRight(z);
+ }
+ z.parent.color = NOIR;
+ z.parent.parent.color = ROUGE;
+ rotateLeft(z.parent.parent);
+ }
+ }
}
- /** Remplace un nœud par un autre dans l’arbre */
- private void transplant(Node u, Node v) {
- if (u.parent == null)
- root = v;
- else if (u == u.parent.left)
- u.parent.left = v;
- else
- u.parent.right = v;
-
- if (v != null)
- v.parent = u.parent;
+ racine.color = NOIR;
+ }
+
+ /** Remplace un nœud par un autre dans l’arbre */
+ private void transplant(Noeud u, Noeud v) {
+ if (u.parent == null) {
+ racine = v;
+ } else if (u == u.parent.gauche) {
+ u.parent.gauche = v;
+ } else {
+ u.parent.droit = v;
}
- /** Renvoie le minimum du sous-arbre */
- private Node minimum(Node x) {
- while (x.left != null)
- x = x.left;
- return x;
+ if (v != null) {
+ v.parent = u.parent;
}
+ }
- /**
- * Correction après suppression. Restaure les propriétés Rouge-Noir.
- */
- private void fixAfterDelete(Node x, Node parent) {
- while ((x != root) && (x == null || x.color == BLACK)) {
- if (parent != null && x == parent.left) {
- Node w = parent.right;
-
- if (w != null && w.color == RED) {
- w.color = BLACK;
- parent.color = RED;
- rotateLeft(parent);
- w = parent.right;
- }
-
- if ((w == null)
- || ((w.left == null || w.left.color == BLACK) && (w.right == null || w.right.color == BLACK))) {
- if (w != null)
- w.color = RED;
-
- x = parent;
- parent = x.parent;
- } else {
- if (w.right == null || w.right.color == BLACK) {
- if (w.left != null)
- w.left.color = BLACK;
-
- w.color = RED;
- rotateRight(w);
- w = parent.right;
- }
-
- if (w != null)
- w.color = parent.color;
-
- parent.color = BLACK;
-
- if (w != null && w.right != null)
- w.right.color = BLACK;
-
- rotateLeft(parent);
- x = root;
- break;
- }
- } else {
- if (parent == null)
- break;
-
- Node w = parent.left;
-
- if (w != null && w.color == RED) {
- w.color = BLACK;
- parent.color = RED;
- rotateRight(parent);
- w = parent.left;
- }
-
- if ((w == null)
- || ((w.right == null || w.right.color == BLACK) && (w.left == null || w.left.color == BLACK))) {
- if (w != null)
- w.color = RED;
-
- x = parent;
- parent = x.parent;
- } else {
- if (w.left == null || w.left.color == BLACK) {
- if (w.right != null)
- w.right.color = BLACK;
-
- w.color = RED;
- rotateLeft(w);
- w = parent.left;
- }
-
- if (w != null)
- w.color = parent.color;
-
- parent.color = BLACK;
-
- if (w != null && w.left != null)
- w.left.color = BLACK;
-
- rotateRight(parent);
- x = root;
- break;
- }
- }
- }
-
- if (x != null)
- x.color = BLACK;
+ /** Renvoie le minimum du sous-arbre */
+ private Noeud minimum(Noeud x) {
+ while (x.gauche != null) {
+ x = x.gauche;
}
- @Override
- public boolean add(E e) {
- Objects.requireNonNull(e);
-
- // Arbre vide : nouvelle racine noire
- if (root == null) {
- root = new Node(e, null);
- root.color = BLACK;
- size = 1;
- return true;
- }
-
- Node cur = root, parent = null;
- int cmp = 0;
-
- // Recherche de la position d'insertion
- while (cur != null) {
- parent = cur;
- cmp = e.compareTo(cur.key);
-
- if (cmp < 0)
- cur = cur.left;
- else if (cmp > 0)
- cur = cur.right;
- else
- return false; // pas de doublons
- }
-
- Node node = new Node(e, parent);
-
- if (cmp < 0)
- parent.left = node;
- else
- parent.right = node;
-
- // Correction RB après insertion
- fixAfterInsert(node);
- size++;
-
- return true;
+ return x;
+ }
+
+ /**
+ * Correction après suppression. Restaure les propriétés Rouge-Noir.
+ */
+ private void fixAfterDelete(Noeud x, Noeud parent) {
+ while ((x != racine) && (x == null || x.color == NOIR)) {
+ if (parent != null && x == parent.gauche) {
+ Noeud w = parent.droit;
+
+ if (w != null && w.color == ROUGE) {
+ w.color = NOIR;
+ parent.color = ROUGE;
+ rotateLeft(parent);
+ w = parent.droit;
+ }
+
+ if ((w == null) || ((w.gauche == null || w.gauche.color == NOIR)
+ && (w.droit == null || w.droit.color == NOIR))) {
+ if (w != null) {
+ w.color = ROUGE;
+ }
+
+ x = parent;
+ parent = x.parent;
+ } else {
+ if (w.droit == null || w.droit.color == NOIR) {
+ if (w.gauche != null) {
+ w.gauche.color = NOIR;
+ }
+
+ w.color = ROUGE;
+ rotateRight(w);
+ w = parent.droit;
+ }
+
+ if (w != null) {
+ w.color = parent.color;
+ }
+
+ parent.color = NOIR;
+
+ if (w != null && w.droit != null) {
+ w.droit.color = NOIR;
+ }
+
+ rotateLeft(parent);
+ x = racine;
+ break;
+ }
+ } else {
+ if (parent == null) {
+ break;
+ }
+
+ Noeud w = parent.gauche;
+
+ if (w != null && w.color == ROUGE) {
+ w.color = NOIR;
+ parent.color = ROUGE;
+ rotateRight(parent);
+ w = parent.gauche;
+ }
+
+ if ((w == null) || ((w.droit == null || w.droit.color == NOIR)
+ && (w.gauche == null || w.gauche.color == NOIR))) {
+ if (w != null) {
+ w.color = ROUGE;
+ }
+
+ x = parent;
+ parent = x.parent;
+ } else {
+ if (w.gauche == null || w.gauche.color == NOIR) {
+ if (w.droit != null) {
+ w.droit.color = NOIR;
+ }
+
+ w.color = ROUGE;
+ rotateLeft(w);
+ w = parent.gauche;
+ }
+
+ if (w != null) {
+ w.color = parent.color;
+ }
+
+ parent.color = NOIR;
+
+ if (w != null && w.gauche != null) {
+ w.gauche.color = NOIR;
+ }
+
+ rotateRight(parent);
+ x = racine;
+ break;
+ }
+ }
}
- /** Recherche un nœud contenant la clé */
- private Node findNode(E e) {
- Node cur = root;
+ if (x != null) {
+ x.color = NOIR;
+ }
+ }
+
+ @Override
+ public boolean add(E e) {
+ Objects.requireNonNull(e);
+
+ // Arbre vide : nouvelle racine noire
+ if (racine == null) {
+ racine = new Noeud(e, null);
+ racine.color = NOIR;
+ taille = 1;
+ return true;
+ }
- while (cur != null) {
- int cmp = e.compareTo(cur.key);
+ Noeud cur = racine;
+ Noeud parent = null;
+ int cmp = 0;
+
+ // Recherche de la position d'insertion
+ while (cur != null) {
+ parent = cur;
+ cmp = e.compareTo(cur.cle);
+
+ if (cmp < 0) {
+ cur = cur.gauche;
+ } else if (cmp > 0) {
+ cur = cur.droit;
+ } else {
+ return false; // pas de doublons
+ }
+ }
- if (cmp == 0)
- return cur;
- if (cmp < 0)
- cur = cur.left;
- else
- cur = cur.right;
- }
+ Noeud node = new Noeud(e, parent);
- return null;
+ if (cmp < 0) {
+ parent.gauche = node;
+ } else {
+ parent.droit = node;
}
- @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;
- }
+ // Correction RB après insertion
+ fixAfterInsert(node);
+ taille++;
+
+ return true;
+ }
+
+ /** Recherche un nœud contenant la clé */
+ 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;
+ }
}
- @Override
- public boolean remove(Object o) {
- if (o == null)
- return false;
-
- E e;
-
- try {
- e = (E) o;
- } catch (ClassCastException ex) {
- return false;
- }
-
- Node z = findNode(e);
-
- if (z == null)
- return false;
-
- Node y = z;
- boolean yOriginalColor = y.color;
- Node x;
- Node xParent;
-
- // Cas 1 : un seul enfant
- if (z.left == null) {
- x = z.right;
- xParent = z.parent;
- transplant(z, z.right);
- } else if (z.right == null) {
- x = z.left;
- xParent = z.parent;
- transplant(z, z.left);
- }
-
- // Cas 2 : deux enfants → successeur
- else {
- y = minimum(z.right);
- yOriginalColor = y.color;
- x = y.right;
-
- if (y.parent == z) {
- if (x != null)
- x.parent = y;
- xParent = y;
- } else {
- transplant(y, y.right);
- y.right = z.right;
-
- if (y.right != null)
- y.right.parent = y;
-
- xParent = y.parent;
- }
-
- transplant(z, y);
- y.left = z.left;
-
- if (y.left != null)
- y.left.parent = y;
-
- y.color = z.color;
- }
-
- if (yOriginalColor == BLACK)
- fixAfterDelete(x, xParent);
-
- size--;
- return true;
+ return null;
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ if (o == null) {
+ return false;
}
- @Override
- public Iterator iterator() {
- return new Iterator() {
- private final Stack stack = initStack(root);
-
- private Stack initStack(Node r) {
- Stack s = new Stack<>();
- Node cur = r;
-
- while (cur != null) {
- s.push(cur);
- cur = cur.left;
- }
-
- return s;
- }
-
- @Override
- public boolean hasNext() {
- return !stack.isEmpty();
- }
-
- @Override
- public E next() {
- if (!hasNext())
- throw new NoSuchElementException();
-
- Node n = stack.pop();
- E res = n.key;
- Node cur = n.right;
-
- // Descente maximale à gauche
- while (cur != null) {
- stack.push(cur);
- cur = cur.left;
- }
-
- return res;
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
- };
+ try {
+ @SuppressWarnings("unchecked")
+ E e = (E) o;
+ return findNode(e) != null;
+ } catch (ClassCastException ex) {
+ return false;
}
+ }
- @Override
- public int size() {
- return size;
+ @Override
+ public boolean remove(Object o) {
+ if (o == null) {
+ return false;
}
- @Override
- public boolean isEmpty() {
- return size == 0;
+ E e;
+
+ try {
+ e = (E) o;
+ } catch (ClassCastException ex) {
+ return false;
}
- @Override
- public void clear() {
- root = null;
- size = 0;
+ Noeud z = findNode(e);
+
+ if (z == null) {
+ return false;
}
- @Override
- public Object[] toArray() {
- Object[] arr = new Object[size];
- int i = 0;
+ Noeud y = z;
+ boolean yorigColor = y.color;
+ Noeud x;
+ Noeud xparent;
+
+ // Cas 1 : un seul enfant
+ if (z.gauche == null) {
+ x = z.droit;
+ xparent = z.parent;
+ transplant(z, z.droit);
+ } else if (z.droit == null) {
+ x = z.gauche;
+ xparent = z.parent;
+ transplant(z, z.gauche);
+ } else { // Cas 2 : deux enfants → successeur
+ y = minimum(z.droit);
+ yorigColor = y.color;
+ x = y.droit;
+
+ if (y.parent == z) {
+ if (x != null) {
+ x.parent = y;
+ }
+
+ xparent = y;
+ } else {
+ transplant(y, y.droit);
+ y.droit = z.droit;
+
+ if (y.droit != null) {
+ y.droit.parent = y;
+ }
+
+ xparent = y.parent;
+ }
+
+ transplant(z, y);
+ y.gauche = z.gauche;
+
+ if (y.gauche != null) {
+ y.gauche.parent = y;
+ }
+
+ y.color = z.color;
+ }
- for (E e : this)
- arr[i++] = e;
+ if (yorigColor == NOIR) {
+ fixAfterDelete(x, xparent);
+ }
- return arr;
+ taille--;
+ return true;
+ }
+
+ @Override
+ public Iterator iterator() {
+ return new Iterator() {
+ private final Stack stack = initStack(racine);
+
+ private Stack initStack(Noeud r) {
+ Stack s = new Stack<>();
+ Noeud cur = r;
+
+ while (cur != null) {
+ s.push(cur);
+ cur = cur.gauche;
+ }
+
+ return s;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return !stack.isEmpty();
+ }
+
+ @Override
+ public E next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+
+ Noeud n = stack.pop();
+ E res = n.cle;
+ Noeud cur = n.droit;
+
+ // Descente maximale à gauche
+ while (cur != null) {
+ stack.push(cur);
+ cur = cur.gauche;
+ }
+
+ return res;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ @Override
+ public int size() {
+ return taille;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return taille == 0;
+ }
+
+ @Override
+ public void clear() {
+ racine = null;
+ taille = 0;
+ }
+
+ @Override
+ public Object[] toArray() {
+ Object[] arr = new Object[taille];
+ int i = 0;
+
+ for (E e : this) {
+ arr[i++] = e;
}
- @Override
- public T[] toArray(T[] a) {
- if (a.length < size)
- a = (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
+ return arr;
+ }
- int i = 0;
+ @Override
+ public T[] toArray(T[] a) {
+ if (a.length < taille) {
+ a = (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), taille);
+ }
- for (E e : this)
- a[i++] = (T) e;
+ int i = 0;
- if (a.length > size)
- a[size] = null;
+ for (E e : this) {
+ a[i++] = (T) e;
+ }
- return a;
+ if (a.length > taille) {
+ a[taille] = null;
}
- @Override
- public boolean containsAll(Collection> c) {
- for (Object o : c)
- if (!contains(o))
- return false;
- return true;
+ return a;
+ }
+
+ @Override
+ public boolean containsAll(Collection> c) {
+ for (Object o : c) {
+ if (!contains(o)) {
+ return false;
+ }
}
- @Override
- public boolean addAll(Collection extends E> c) {
- boolean changed = false;
- for (E e : c)
- changed |= add(e);
- return changed;
+ return true;
+ }
+
+ @Override
+ public boolean addAll(Collection extends E> c) {
+ boolean changed = false;
+ for (E e : c) {
+ changed |= add(e);
}
- @Override
- public boolean removeAll(Collection> c) {
- boolean changed = false;
- for (Object o : c)
- changed |= remove(o);
- return changed;
+ return changed;
+ }
+
+ @Override
+ public boolean removeAll(Collection> c) {
+ boolean changed = false;
+ for (Object o : c) {
+ changed |= remove(o);
}
- @Override
- public boolean retainAll(Collection> c) {
- List toRemove = new ArrayList<>();
+ return changed;
+ }
- for (E e : this)
- if (!c.contains(e))
- toRemove.add(e);
+ @Override
+ public boolean retainAll(Collection> c) {
+ List toRemove = new ArrayList<>();
- for (E e : toRemove)
- remove(e);
+ for (E e : this) {
+ if (!c.contains(e)) {
+ toRemove.add(e);
+ }
+ }
- return !toRemove.isEmpty();
+ for (E e : toRemove) {
+ remove(e);
}
+
+ return !toRemove.isEmpty();
+ }
}
diff --git a/src/test/java/collection/ArbreBinaireRechercheTest.java b/src/test/java/collection/ArbreBinaireRechercheTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..66c29952789cf189b5fd28e40bae56b8944d6474
--- /dev/null
+++ b/src/test/java/collection/ArbreBinaireRechercheTest.java
@@ -0,0 +1,308 @@
+package collection;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class ArbreBinaireRechercheTest {
+
+ private ArbreBinaireRecherche arbre;
+
+ @BeforeEach
+ void setUp() {
+ arbre = new ArbreBinaireRecherche<>();
+ }
+
+ @Test
+ void testAdd() {
+ assertTrue(arbre.add(5));
+ assertTrue(arbre.add(3));
+ assertTrue(arbre.add(7));
+ assertFalse(arbre.add(5)); // doublon
+
+ assertEquals(3, arbre.size());
+ }
+
+ @Test
+ void testContains() {
+ arbre.add(5);
+ arbre.add(2);
+ arbre.add(8);
+
+ assertTrue(arbre.contains(5));
+ assertTrue(arbre.contains(2));
+ assertFalse(arbre.contains(10));
+ assertFalse(arbre.contains(null));
+ }
+
+ @Test
+ void testRemoveFeuille() {
+ arbre.add(5);
+ arbre.add(3);
+ arbre.add(8);
+
+ assertTrue(arbre.remove(3));
+ assertFalse(arbre.contains(3));
+ assertEquals(2, arbre.size());
+ }
+
+ @Test
+ void testRemoveNoeudAvecUnEnfant() {
+ arbre.add(5);
+ arbre.add(3);
+ arbre.add(2); // enfant de 3
+
+ assertTrue(arbre.remove(3));
+ assertTrue(arbre.contains(2));
+ assertFalse(arbre.contains(3));
+ assertEquals(2, arbre.size());
+ }
+
+ @Test
+ void testRemoveNoeudDeuxEnfants() {
+ arbre.add(5);
+ arbre.add(3);
+ arbre.add(7);
+ arbre.add(6);
+ arbre.add(8);
+
+ assertTrue(arbre.remove(7));
+ assertFalse(arbre.contains(7));
+ assertEquals(4, arbre.size());
+ }
+
+ @Test
+ void testIteratorOrdreCroissant() {
+ arbre.add(5);
+ arbre.add(2);
+ arbre.add(8);
+ arbre.add(1);
+ arbre.add(3);
+
+ Iterator it = arbre.iterator();
+
+ assertEquals(1, it.next());
+ assertEquals(2, it.next());
+ assertEquals(3, it.next());
+ assertEquals(5, it.next());
+ assertEquals(8, it.next());
+ assertFalse(it.hasNext());
+ }
+
+ @Test
+ void testClear() {
+ arbre.add(4);
+ arbre.add(1);
+ arbre.add(9);
+
+ arbre.clear();
+
+ assertTrue(arbre.isEmpty());
+ assertEquals(0, arbre.size());
+ assertFalse(arbre.contains(4));
+ }
+
+ @Test
+ void testToArray() {
+ arbre.add(3);
+ arbre.add(1);
+ arbre.add(2);
+
+ Object[] arr = arbre.toArray();
+
+ assertEquals(3, arr.length);
+ assertArrayEquals(new Object[] { 1, 2, 3 }, arr);
+ }
+
+ @Test
+ void testAddAll() {
+ List list = Arrays.asList(5, 2, 8);
+
+ assertTrue(arbre.addAll(list));
+ assertEquals(3, arbre.size());
+ assertTrue(arbre.contains(8));
+ }
+
+ @Test
+ void testRemoveAll() {
+ arbre.add(5);
+ arbre.add(2);
+ arbre.add(8);
+
+ List list = Arrays.asList(2, 8);
+
+ assertTrue(arbre.removeAll(list));
+ assertFalse(arbre.contains(2));
+ assertFalse(arbre.contains(8));
+ assertTrue(arbre.contains(5));
+ }
+
+ @Test
+ void testRetainAll() {
+ arbre.add(5);
+ arbre.add(2);
+ arbre.add(8);
+
+ List list = Arrays.asList(5);
+
+ assertTrue(arbre.retainAll(list));
+ assertTrue(arbre.contains(5));
+ assertFalse(arbre.contains(2));
+ assertFalse(arbre.contains(8));
+ assertEquals(1, arbre.size());
+ }
+
+ @Test
+ void testContainsAvecTypeIncorrect() {
+ arbre.add(5);
+ arbre.add(3);
+
+ // Un type incompatible doit entraîner catch(ClassCastException) → false
+ assertFalse(arbre.contains("texte")); // String ≠ Integer
+ }
+
+ @Test
+ void testRemoveNull() {
+ arbre.add(5);
+
+ assertFalse(arbre.remove(null)); // ne doit jamais lancer d’exception
+ assertEquals(1, arbre.size());
+ assertTrue(arbre.contains(5));
+ }
+
+ @Test
+ void testRemoveRacineNull() {
+ // racine = null
+ assertTrue(arbre.isEmpty());
+
+ assertFalse(arbre.remove(10)); // retirer un élément dans un arbre vide => false
+ assertTrue(arbre.isEmpty());
+ }
+
+ @Test
+ void testRemoveSansException() {
+ arbre.add(10);
+ arbre.add(5);
+ arbre.add(15);
+
+ // Cas normaux
+ assertDoesNotThrow(() -> arbre.remove(5));
+ assertDoesNotThrow(() -> arbre.remove(15));
+ assertDoesNotThrow(() -> arbre.remove(10));
+
+ // Retrait sur arbre vide
+ assertDoesNotThrow(() -> arbre.remove(999));
+
+ // Retrait d’un null
+ assertDoesNotThrow(() -> arbre.remove(null));
+ }
+
+ @Test
+ void testRemoveAvecSuccesseurProfond() {
+
+ arbre.add(10);
+ arbre.add(5);
+ arbre.add(20);
+ arbre.add(15);
+ arbre.add(13); // successeur profond
+
+ // Suppression du nœud ayant deux enfants
+ assertTrue(arbre.remove(10));
+
+ // Le successeur (13) doit avoir remplacé la racine
+ Iterator it = arbre.iterator();
+ assertEquals(5, it.next());
+ assertEquals(13, it.next()); // remplace 10
+ assertEquals(15, it.next());
+ assertEquals(20, it.next());
+ assertFalse(it.hasNext());
+ }
+
+ @Test
+ void testRemoveRacineAvecUnEnfant() {
+ arbre.add(10);
+ arbre.add(20); // enfant droit unique
+
+ assertTrue(arbre.remove(10));
+
+ // La racine doit être remplacée par l’enfant (20)
+ assertEquals(20, arbre.iterator().next());
+ assertEquals(1, arbre.size());
+ }
+
+ @Test
+ void testIsEmpty() {
+ ArbreBinaireRecherche a = new ArbreBinaireRecherche<>();
+
+ // L'arbre vide
+ assertTrue(a.isEmpty());
+
+ // Après insertion
+ a.add(1);
+ assertFalse(a.isEmpty());
+
+ // Après suppression
+ a.remove(1);
+ assertTrue(a.isEmpty());
+ }
+
+ @Test
+ void testToArrayComplet() {
+ arbre.add(4);
+ arbre.add(1);
+ arbre.add(3);
+ arbre.add(2);
+
+ Object[] arr = arbre.toArray();
+
+ assertEquals(4, arr.length);
+ assertArrayEquals(new Object[] { 1, 2, 3, 4 }, arr);
+
+ // Vérification cohérence avec iterator()
+ int index = 0;
+ for (int value : arbre) {
+ assertEquals(value, arr[index++]);
+ }
+ }
+
+ @Test
+ void testContainsAll() {
+ arbre.add(5);
+ arbre.add(2);
+ arbre.add(8);
+
+ // Tous présents
+ assertTrue(arbre.containsAll(Arrays.asList(2, 5)));
+
+ // Un absent
+ assertFalse(arbre.containsAll(Arrays.asList(2, 10)));
+
+ // Collection vide → doit être true
+ assertTrue(arbre.containsAll(Arrays.asList()));
+
+ // Mauvais type → contains(o) doit retourner false
+ assertFalse(arbre.containsAll(Arrays.asList("test")));
+ }
+
+ @Test
+ void testToArrayGenericRetourNull() {
+ arbre.add(5);
+ arbre.add(2);
+ arbre.add(9);
+
+ Integer[] cible = new Integer[3];
+
+ // L’implémentation actuelle doit renvoyer null
+ assertNull(arbre.toArray(cible));
+ }
+}
diff --git a/src/test/java/collection/RedBlackTree.java b/src/test/java/collection/RedBlackTree.java
new file mode 100644
index 0000000000000000000000000000000000000000..efc89c2d497288ecdc173fd80dfebf97bc642a2b
--- /dev/null
+++ b/src/test/java/collection/RedBlackTree.java
@@ -0,0 +1,136 @@
+package collection;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class RedBlackTreeTest {
+
+ private RedBlackTree tree;
+
+ @BeforeEach
+ void setUp() {
+ tree = new RedBlackTree<>();
+ }
+
+ @Test
+ void testAddAndContains() {
+ assertTrue(tree.add(10));
+ assertTrue(tree.contains(10));
+ assertFalse(tree.add(10)); // pas de doublons
+ }
+
+ @Test
+ void testRemove() {
+ tree.add(20);
+ tree.add(10);
+ tree.add(30);
+
+ assertTrue(tree.remove(20));
+ assertFalse(tree.contains(20));
+ assertFalse(tree.remove(40)); // élément inexistant
+ }
+
+ @Test
+ void testSizeAndIsEmpty() {
+ assertTrue(tree.isEmpty());
+ tree.add(1);
+ tree.add(2);
+ tree.add(3);
+
+ assertEquals(3, tree.size());
+ assertFalse(tree.isEmpty());
+ }
+
+ @Test
+ void testClear() {
+ tree.add(5);
+ tree.add(15);
+ tree.clear();
+ assertEquals(0, tree.size());
+ assertTrue(tree.isEmpty());
+ }
+
+ @Test
+ void testIterator() {
+ tree.add(3);
+ tree.add(1);
+ tree.add(4);
+ tree.add(2);
+
+ Iterator it = tree.iterator();
+ int[] expectedOrder = { 1, 2, 3, 4 };
+ int i = 0;
+
+ while (it.hasNext()) {
+ assertEquals(expectedOrder[i++], it.next());
+ }
+
+ assertEquals(expectedOrder.length, i);
+ }
+
+ @Test
+ void testToArray() {
+ tree.add(7);
+ tree.add(3);
+ tree.add(9);
+
+ Object[] arr = tree.toArray();
+ Arrays.sort(arr); // pour comparaison
+ assertArrayEquals(new Object[] { 3, 7, 9 }, arr);
+ }
+
+ @Test
+ void testToArrayWithType() {
+ tree.add(5);
+ tree.add(1);
+ tree.add(8);
+
+ Integer[] arr = new Integer[3];
+ arr = tree.toArray(arr);
+
+ Arrays.sort(arr);
+ assertArrayEquals(new Integer[] { 1, 5, 8 }, arr);
+ }
+
+ @Test
+ void testAddAllAndContainsAll() {
+ List list = Arrays.asList(10, 20, 30);
+ assertTrue(tree.addAll(list));
+ assertTrue(tree.containsAll(list));
+ }
+
+ @Test
+ void testRemoveAll() {
+ tree.add(1);
+ tree.add(2);
+ tree.add(3);
+
+ List toRemove = Arrays.asList(2, 3, 4);
+ assertTrue(tree.removeAll(toRemove));
+ assertFalse(tree.contains(2));
+ assertFalse(tree.contains(3));
+ assertTrue(tree.contains(1));
+ }
+
+ @Test
+ void testRetainAll() {
+ tree.add(1);
+ tree.add(2);
+ tree.add(3);
+
+ List toRetain = Arrays.asList(2, 3, 4);
+ assertTrue(tree.retainAll(toRetain));
+ assertFalse(tree.contains(1));
+ assertTrue(tree.contains(2));
+ assertTrue(tree.contains(3));
+ }
+}