Skip to content
Snippets Groups Projects
Commit c9783796 authored by Sarah CHERCHEM's avatar Sarah CHERCHEM
Browse files

finalisation du tp

parent c96750e8
No related branches found
No related tags found
No related merge requests found
...@@ -2,10 +2,10 @@ import Graph.*; ...@@ -2,10 +2,10 @@ import Graph.*;
import GraphClasses.*; import GraphClasses.*;
import RandomTreeAlgos.BreadthFirstSearch; import RandomTreeAlgos.BreadthFirstSearch;
import Graphics.*; import Graphics.*;
import TreesAlgo.*;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.*;
import java.util.Random;
import javax.swing.JFrame; import javax.swing.JFrame;
...@@ -21,24 +21,58 @@ public class Main { ...@@ -21,24 +21,58 @@ public class Main {
public static void main(String argv[]) throws InterruptedException { public static void main(String argv[]) throws InterruptedException {
Graph graph = chooseFromGraphFamily(); Graph graph = chooseFromGraphFamily();
ArrayList<Edge> randomTree = null;
int noOfSamples = 10; int noOfSamples = 10;
// Tester l'algorithme Prim
System.out.println("-------------------Testing Prim Algorithm------------------------");
testAlgorithm(new Prim(graph), noOfSamples);
// Tester l'algorithme AldousBroder
System.out.println("-------------------Testing AldousBroder Algorithm----------------");
testAlgorithm(new AldousBroder(graph), noOfSamples);
// Tester l'algorithme Contraction
System.out.println("------------------Testing Contraction Algorithm-----------------");
testAlgorithm(new Contraction(graph), noOfSamples);
// Tester l'algorithme Insertion
System.out.println("--------------------Testing Insertion Algorithm-------------------");
testAlgorithm(new Insertion(graph), noOfSamples);
System.out.println("---------------------Testing Wilson Algorithm----------------------");
testAlgorithm(new Wilson(graph), noOfSamples);
// Tester l'algorithme RandomSearch
System.out.println("---------------------Testing RandomSearch Algorithm----------------");
testAlgorithm(new RandomSearch(graph), noOfSamples);
}
private static void testAlgorithm(AbstractArbreCouvrant algorithm, int noOfSamples) {
Graph graph = chooseFromGraphFamily(); // Créer un nouveau graphe pour chaque test
ArrayList<Edge> randomTree = null;
Stats stats = new Stats(noOfSamples); Stats stats = new Stats(noOfSamples);
for (int i = 0; i < noOfSamples; i++) { for (int i = 0; i < noOfSamples; i++) {
randomTree = genTree(graph); randomTree = genTree(graph, algorithm); // Utilisation de l'algorithme
stats.update(randomTree); stats.update(randomTree);
} }
stats.print(); stats.print();
if (grid != null) {
if (grid != null) showGrid(grid, randomTree); try {
showGrid(grid, randomTree);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
} }
private static Graph chooseFromGraphFamily() { private static Graph chooseFromGraphFamily() {
// Parametriser ici cette fonction afin de pouvoir choisir // Parametriser ici cette fonction afin de pouvoir choisir
// quelle classe de graphe utiliser // quelle classe de graphe utiliser
grid = new Grid(1920 / 11, 1080 / 11); grid = new Grid(1920 / 20, 1080 / 20);
Graph graph = grid.graph; Graph graph = grid.graph;
// Graph graph = new Complete(400).graph; // Graph graph = new Complete(400).graph;
//Graph graph = new ErdosRenyi(1_000, 100).graph; //Graph graph = new ErdosRenyi(1_000, 100).graph;
...@@ -46,8 +80,8 @@ public class Main { ...@@ -46,8 +80,8 @@ public class Main {
return graph; return graph;
} }
public static ArrayList<Edge> genTree(Graph graph) { public static ArrayList<Edge> genTree(Graph graph,ArbreCouvrant arbre) {
ArrayList<Edge> randomTree; /* ArrayList<Edge> randomTree;
// TOOO : modifier l'algorithme utilisé ici // TOOO : modifier l'algorithme utilisé ici
// ou bien parametriser à l'aide de la ligne de commande // ou bien parametriser à l'aide de la ligne de commande
...@@ -58,7 +92,14 @@ public class Main { ...@@ -58,7 +92,14 @@ public class Main {
randomTree = new ArrayList<>(); randomTree = new ArrayList<>();
for (Arc a : randomArcTree) randomTree.add(a.support); for (Arc a : randomArcTree) randomTree.add(a.support);
return randomTree; return randomTree;*/
Set<Edge> arbreCouvrant = arbre.arbreCouvrant(); // Récupérer l'arbre couvrant minimal
if (arbreCouvrant == null || arbreCouvrant.isEmpty()) {
return new ArrayList<>(); // Retourner une liste vide si l'arbre est invalide
}
return new ArrayList<>(arbreCouvrant);
} }
...@@ -139,7 +180,7 @@ public class Main { ...@@ -139,7 +180,7 @@ public class Main {
// Pour générer un fichier image. // Pour générer un fichier image.
try { try {
laby.saveImage("resources/random.png"); laby.saveImage("resources/search.png");
} catch (IOException e1) { } catch (IOException e1) {
e1.printStackTrace(); e1.printStackTrace();
} }
......
...@@ -32,7 +32,7 @@ public class BreadthFirstSearch { ...@@ -32,7 +32,7 @@ public class BreadthFirstSearch {
} }
} }
private BreadthFirstSearch (Graph graph) { public BreadthFirstSearch (Graph graph) {
this.graph = graph; this.graph = graph;
this.frontier = new LinkedList<>(); this.frontier = new LinkedList<>();
this.tree = new ArrayList<>(); this.tree = new ArrayList<>();
......
package Structures;
import Graph.Edge;
import Graph.Graph;
import java.util.*;
public class ContractionGraph {
private List<LinkedList<Integer>> incidence; // Liste des arêtes incidentes pour chaque sommet
private final List<Integer> extrimite1 = new ArrayList<>();
private final List<Integer> extrimite2 = new ArrayList<>();
private final List<Edge> initialEdges = new ArrayList<>();
public ContractionGraph(Graph graph) {
// Initialisation de la liste incidence avec une nouvelle ArrayList pour chaque sommet
this.incidence = new ArrayList<>(graph.order);
for (int i = 0; i < graph.order; i++) {
incidence.add(new LinkedList<>()); // Initialisation de la liste pour chaque sommet
}
// Parcours tous les sommets du graphe
for (int vertex = 0; vertex < graph.order; vertex++) {
// Récupère les arêtes sortantes du sommet
for (var arc : graph.outEdges(vertex)) {
Edge edge = arc.support;
// Ajout des arêtes aux listes
initialEdges.add(edge);
extrimite1.add(edge.getSource());
extrimite2.add(edge.getDest());
// Ajout de l'indice de l'arête dans la liste d'incidences des deux sommets
incidence.get(edge.getSource()).add(extrimite1.size());
incidence.get(edge.getDest()).add(extrimite1.size());
}
}
}
// Vérifie si une arête est une boucle
public boolean boucle(int indexEdge) {
return (extrimite1.get(indexEdge).equals(extrimite2.get(indexEdge)));
}
// Contraction de l'arête spécifiée
public void contract(int edgeIndex) {
if (edgeIndex < 0 || edgeIndex >= extrimite1.size()) {
return;
}
int sommet1 = this.extrimite1.get(edgeIndex);
int sommet2 = this.extrimite2.get(edgeIndex);
if (boucle(edgeIndex)) return;
// Pour chaque arête incidente sur sommet2
for (int edge : incidence.get(sommet2)) {
if (edge < 0 || edge >= extrimite1.size()) {
continue; // Ignore l'arête invalide
}
// Ajouter l'arête incidente à sommet1 si elle n'est pas déjà présente
if (extrimite1.get(edge) == sommet1 || extrimite2.get(edge) == sommet1) {
this.incidence.get(sommet1).add(edge);
}
// Relier l'arête à sommet1
if (extrimite1.get(edge) == sommet2) {
this.extrimite1.set(edge, sommet1);
}
if (extrimite2.get(edge) == sommet2) {
this.extrimite2.set(edge, sommet1);
}
}
}
// Retourne la liste des arêtes initiales
public List<Edge> getInitialEdges() {
return initialEdges;
}
public List<Integer> getExtrimite1() {
return extrimite1;
}
public List<Integer> getExtrimite2() {
return extrimite2;
}
}
package TreesAlgo;
import java.util.*;
public class UnionFind<T> {
private Map<T, T> parent;
private Map<T, Integer> rank;
public UnionFind() {
parent = new HashMap<>();
rank = new HashMap<>();
}
// Trouver le représentant de l'ensemble, avec compression de chemin
public T find(T x) {
if (!parent.containsKey(x)) {
parent.put(x, x);
rank.put(x, 0);
}
if (!x.equals(parent.get(x))) {
parent.put(x, find(parent.get(x))); // Compression de chemin
}
return parent.get(x);
}
// Fusionner deux ensembles
public void union(T x, T y) {
T rootX = find(x);
T rootY = find(y);
if (!rootX.equals(rootY)) {
// Union par rang (hauteur)
if (rank.get(rootX) > rank.get(rootY)) {
parent.put(rootY, rootX);
} else if (rank.get(rootX) < rank.get(rootY)) {
parent.put(rootX, rootY);
} else {
parent.put(rootY, rootX);
rank.put(rootX, rank.get(rootX) + 1);
}
}
}
// Vérifie si deux éléments appartiennent au même ensemble
public boolean connected(T x, T y) {
return find(x).equals(find(y));
}
}
package TreesAlgo;
import Graph.Graph;
import Graph.Edge;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
public abstract class AbstractArbreCouvrant implements ArbreCouvrant{
protected final Graph graph;
protected final Random generator = new Random();
protected final Set<Edge> arbre = new HashSet<>();
public AbstractArbreCouvrant(Graph graph) {
this.graph = graph;
}
}
package TreesAlgo;
import Graph.Edge;
import Graph.Graph;
import Graph.Arc;
import java.util.HashSet;
import java.util.Set;
public class AldousBroder extends AbstractArbreCouvrant {
private int sommetActuel; // Sommet courant de la marche
private final Set<Integer> sommetVisite; // Ensemble des sommets visités
public AldousBroder(Graph graph) {
super(graph);
this.sommetVisite = new HashSet<>();
this.sommetActuel = generator.nextInt(graph.order); // Sommet initial aléatoire
this.sommetVisite.add(sommetActuel); // Marquer le sommet initial
marcher(); // Lancer la marche
}
public void marcher() {
while (sommetVisite.size() < graph.order) {
// Sélection aléatoire d'un arc sortant
Arc arc = graph.outEdges(sommetActuel)[generator.nextInt(graph.outEdges(sommetActuel).length)];
// Récupérer le sommet voisin via l'arc
int voisin = arc.getDest();
// Si le voisin n'est pas visité, ajouter l'arête dans l'arbre
if (sommetVisite.add(voisin)) { // La méthode add() retourne false si le voisin est déjà présent
arbre.add(arc.support); // Ajouter l'arête supportée
}
// Mettre à jour le sommet actuel
sommetActuel = voisin;
}
}
@Override
public Set<Edge> arbreCouvrant() {
return arbre; // Retourner l'arbre couvrant construit
}
}
package TreesAlgo;
import Graph.Edge;
import java.util.Set;
public interface ArbreCouvrant {
public Set<Edge> arbreCouvrant();
}
package TreesAlgo;
import Graph.Graph;
import Graph.Edge;
import Structures.ContractionGraph;
import java.util.*;
public class Contraction extends AbstractArbreCouvrant {
private final ContractionGraph contractionGraph;
private final TreesAlgo.UnionFind<Integer> unionFind;
private final Node[] nodes; // Tableau pour stocker les informations des sommets
public Contraction(Graph graph) {
super(graph);
this.contractionGraph = new ContractionGraph(graph);
this.unionFind = new TreesAlgo.UnionFind<>();
this.nodes = new Node[graph.getIncidency().size()]; // Initialiser le tableau de noeuds
Arrays.fill(this.nodes, new Node()); // Initialiser chaque noeud avec un objet Node
}
@Override
public Set<Edge> arbreCouvrant() {
List<Integer> edges = new ArrayList<>();
// Remplir la liste avec des indices d'arêtes
for (int i = 0; i < contractionGraph.getExtrimite1().size(); i++) {
edges.add(i);
}
// Mélanger les arêtes pour les traiter dans un ordre aléatoire
Collections.shuffle(edges);
for (int edgeIndex : edges) {
if (contractionGraph.boucle(edgeIndex)) {
continue; // Passer les boucles
}
// Récupérer les sommets connectés par l'arête
int vertex1 = contractionGraph.getExtrimite1().get(edgeIndex);
int vertex2 = contractionGraph.getExtrimite2().get(edgeIndex);
// Si les sommets sont déjà connectés, ignorer cette arête
if (unionFind.find(vertex1) == unionFind.find(vertex2)) {
continue;
}
// Ajouter l'arête à l'arbre couvrant
arbre.add(contractionGraph.getInitialEdges().get(edgeIndex));
// Union des sommets pour contracter l'arête
unionFind.union(vertex1, vertex2);
// Contracter l'arête dans le graphe
contractionGraph.contract(edgeIndex);
}
return arbre;
}
// Classe interne pour représenter un sommet avec sa profondeur et hauteur
private static class Node {
int depth = 0; // Initialiser à 0 ou à une autre valeur par défaut
int height = 0; // Initialiser à 0 ou à une autre valeur par défaut
}
}
package TreesAlgo;
import Graph.Edge;
import Graph.Graph;
import java.util.*;
public class Insertion extends AbstractArbreCouvrant {
private List<Edge> arretesRestant = new ArrayList<>();
private final TreesAlgo.UnionFind<Integer> forest;
public Insertion(Graph graph) {
super(graph);
this.forest = new TreesAlgo.UnionFind<>();
// Initialiser la liste d'arêtes restantes
for (LinkedList<Edge> edgeList : graph.getIncidency()) {
arretesRestant.addAll(edgeList);
}
}
@Override
public Set<Edge> arbreCouvrant() {
// Mélanger les arêtes pour assurer un tirage aléatoire
Collections.shuffle(arretesRestant, generator);
while (arbre.size() < graph.order - 1) {
// Tirer une arête au hasard
Edge e = arretesRestant.remove(0);
int u = e.getSource();
int v = e.getDest();
// Vérifier si l'ajout de l'arête forme un cycle
if (!forest.connected(u, v)) {
// Si ce n'est pas un cycle, ajouter l'arête à l'arbre couvrant
arbre.add(e);
forest.union(u, v); // Fusionner les ensembles contenant u et v
}
}
return arbre;
}
}
package TreesAlgo;
import Graph.Edge;
import Graph.Graph;
import Graph.Arc;
import java.util.*;
public class Prim extends AbstractArbreCouvrant{
private final Map<Edge,Double> poids=new HashMap<>();
private final PriorityQueue<Edge> queue= new PriorityQueue<>(Comparator.comparingDouble(poids::get));
public Prim(Graph graph) {
super(graph);
genererPoidsAleatoires();
}
private void genererPoidsAleatoires() {
int nbEdge = graph.getEdgeCardinality();
int borneSup = (nbEdge > 500) ? Integer.MAX_VALUE : nbEdge * nbEdge * nbEdge;
// Étape 1 : Attribuer un poids aléatoire [0, 1] à chaque arête
for (int i = 0; i < graph.order; i++) {
if (graph.isVertex(i)) {
for (Edge edge : graph.getIncidency().get(i)) {
if (!poids.containsKey(edge)) { // Assurez-vous de ne pas ajouter deux fois une arête
// Utilisez nextInt() pour obtenir un entier entre 0 et borneSup,
// puis divisez par borneSup pour normaliser le poids entre 0 et 1.
double weight = generator.nextInt(borneSup) / (double) borneSup;
poids.put(edge, weight);
}
}
}
}
}
@Override
public Set<Edge> arbreCouvrant() {
// Étape 1 : Choisir un sommet de départ
int startVertex = 0; // On peut commencer avec n'importe quel sommet
Set<Integer> visited = new HashSet<>();
visited.add(startVertex);
// Étape 2 : Ajouter toutes les arêtes sortantes du sommet choisi dans la priorité
for (Edge edge : graph.getIncidency().get(startVertex)) {
queue.add(edge);
}
// Étape 3 : Boucle principale de Prim
while (!queue.isEmpty()) {
Edge edge = queue.poll(); // Obtenir l'arête de poids minimum
int dest = edge.getDest();
// Si l'une des extrémités de l'arête n'est pas encore visitée, l'ajouter à l'arbre
if (!visited.contains(dest)) {
arbre.add(edge);
visited.add(dest);
// Ajouter toutes les arêtes sortantes de ce sommet dans la queue
for (Edge e : graph.getIncidency().get(dest)) {
if (!visited.contains(e.getDest())) {
queue.add(e);
}
}
}
}
return arbre;
}
}
package TreesAlgo;
import Graph.Arc;
import Graph.Graph;
import Graph.Edge;
import java.util.*;
public class RandomSearch extends AbstractArbreCouvrant {
private Set<Integer> visited= new HashSet<>();
public RandomSearch(Graph graph) {
super(graph);
}
@Override
public Set<Edge> arbreCouvrant() {
// Tirer un sommet aléatoire parmi les sommets existants du graphe
int root = generator.nextInt(graph.order); // Sommet aléatoire entre 0 et graph.order - 1
visited.add(root);
// Liste des arcs à explorer, initialement vide
List<Arc> frontier = new ArrayList<>();
// Ajouter les arcs sortants du sommet de départ à la frontière
for (Arc arc : graph.outEdges(root)) {
frontier.add(arc);
}
// Tant qu'il reste des arcs à explorer
while (!frontier.isEmpty()) {
// Choisir un arc au hasard parmi ceux de la frontière
Collections.shuffle(frontier, generator);
Arc arc = frontier.remove(0); // Retirer l'arc choisi
int dest = arc.getDest();
// Si le sommet destination n'a pas été visité, on l'explore
if (!visited.contains(dest)) {
visited.add(dest);
// Ajouter l'arc (sous forme d'Edge) à l'arbre couvrant
arbre.add(arc.support); // Accéder à l'Edge via le champ 'support' de l'Arc
// Ajouter tous les arcs sortants du sommet destination à la frontière
for (Arc newArc : graph.outEdges(dest)) {
if (!visited.contains(newArc.getDest())) {
frontier.add(newArc); // Ajouter les arcs sortants à la frontière
}
}
}
}
return arbre; // Retourner le Set<Edge>
}
}
\ No newline at end of file
package TreesAlgo;
import Graph.Edge;
import Graph.Graph;
import java.util.*;
public class SuppressionCycle extends AbstractArbreCouvrant {
private final Map<Integer, Integer> parent = new HashMap<>(); // Parent de chaque sommet
private final Set<Integer> visited = new HashSet<>(); // Sommets visités
private final Set<Integer> inCycle = new HashSet<>(); // Sommets dans un cycle
private final List<Edge> edgesInCycle = new ArrayList<>(); // Arêtes à supprimer dans un cycle
private final int root; // Racine de l'arbre
public SuppressionCycle(Graph graph) {
super(graph);
this.root = 0; // Sommet racine (à ajuster si nécessaire)
construireArbre();
}
private void construireArbre() {
// Lancer le DFS à partir du sommet racine
dfsIteratif(root);
supprimerCycles();
}
private void dfsIteratif(int sommet) {
Stack<Integer> stack = new Stack<>();
Stack<Edge> edgeStack = new Stack<>(); // Stack pour garder la trace des arêtes
stack.push(sommet);
visited.add(sommet);
while (!stack.isEmpty()) {
int currSommet = stack.peek();
boolean addedNew = false;
// Parcourir les voisins à travers les arêtes incidentes
for (Edge edge : graph.getIncidency().get(currSommet)) {
int voisin = edge.oppositeExtremity(currSommet);
if (!visited.contains(voisin)) {
// Ajouter l'arête dans l'arbre couvrant
arbre.add(edge);
parent.put(voisin, currSommet); // Mettre à jour le parent
visited.add(voisin);
edgeStack.push(edge); // Empiler l'arête
stack.push(voisin); // Empiler le voisin
addedNew = true;
break; // Sortir de la boucle dès qu'un voisin est ajouté
} else if (inCycle.contains(voisin)) {
// Si on revient à un sommet déjà dans un cycle, un cycle est détecté
System.out.println("Cycle détecté : " + edge);
edgesInCycle.add(edge);
inCycle.add(voisin); // Ajouter le sommet au cycle
return; // Fin de la détection de cycle
} else {
// Si l'arête forme un cycle avec un sommet déjà visité, on ajoute à la liste des arêtes
edgesInCycle.add(edge);
}
}
// Si aucun voisin n'a été ajouté, on retire le sommet de la pile de récursion
if (!addedNew) {
stack.pop();
if (!edgeStack.isEmpty()) {
edgeStack.pop(); // Retirer l'arête associée
}
}
}
}
private void supprimerCycles() {
// Supprimer les cycles détectés
Set<Edge> edgesToRemove = new HashSet<>();
for (Edge edge : edgesInCycle) {
if (arbre.contains(edge)) {
edgesToRemove.add(edge);
System.out.println("Suppression de l'arête : " + edge);
}
}
// Supprimer les arêtes du cycle
arbre.removeAll(edgesToRemove);
}
@Override
public Set<Edge> arbreCouvrant() {
return arbre; // Retourner l'arbre couvrant
}
}
package TreesAlgo;
import Graph.Edge;
import Graph.Graph;
import java.util.*;
import java.util.stream.IntStream;
public class Wilson extends AbstractArbreCouvrant {
private final Set<Integer> sommetVisite = new HashSet<>();
private final Map<Integer, Edge> outArc = new HashMap<>();
public Wilson(Graph graph) {
super(graph);
// Sort vertices in descending order of degree and choose a vertex at each iteration
IntStream.range(0, graph.order)
.boxed()
.sorted(Comparator.comparingInt(graph::degreSommet).reversed())
.forEach(
source -> {
if (sommetVisite.isEmpty()) {
sommetVisite.add(source); // Add the first vertex
} else {
walk(source); // Perform a random walk starting from other vertices
}
}
);
}
private void walk(int source) {
int currentVertex = source;
// Perform a random walk until reaching an already visited vertex
while (!sommetVisite.contains(currentVertex)) {
int rand = generator.nextInt(graph.getIncidency().get(currentVertex).size());
Edge edge = graph.getIncidency().get(currentVertex).get(rand); // Get a random edge
outArc.put(currentVertex, edge); // Record the edge to retrace the path later
currentVertex = edge.oppositeExtremity(currentVertex); // Move to the other endpoint of the edge
}
currentVertex = source;
// Retrace the path and mark vertices as visited
while (!sommetVisite.contains(currentVertex)) {
sommetVisite.add(currentVertex); // Add the vertex to the spanning tree
arbre.add(outArc.get(currentVertex)); // Add the edge to the result
currentVertex = outArc.get(currentVertex).oppositeExtremity(currentVertex); // Move to the other endpoint
}
}
@Override
public Set<Edge> arbreCouvrant() {
return arbre; // Return the spanning tree
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment