From 295507685bc1d4d8fd84778eecaf61a1921b9f36 Mon Sep 17 00:00:00 2001
From: dcisse2
Date: Thu, 23 Oct 2025 17:52:15 +0200
Subject: [PATCH 1/3] [UPDATE]
---
.idea/vcs.xml | 1 -
m1graphs25 | 1 -
2 files changed, 2 deletions(-)
delete mode 160000 m1graphs25
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 95c2cb1..94a25f7 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -2,6 +2,5 @@
-
\ No newline at end of file
diff --git a/m1graphs25 b/m1graphs25
deleted file mode 160000
index 3baf9d1..0000000
--- a/m1graphs25
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 3baf9d19e40b5b9ef6e31f7deb15413679dcf68e
--
GitLab
From 9b2df9e5b8837c9cbadc64dddae8d2b64aa35c45 Mon Sep 17 00:00:00 2001
From: dcisse2
Date: Thu, 30 Oct 2025 00:42:15 +0100
Subject: [PATCH 2/3] [UPDATE]
---
src/main/java/m1graphs2025/Edge.java | 2 +-
src/main/java/m1graphs2025/Graph.java | 99 ++++++---
src/main/java/m1graphs2025/TestGraphsPW2.java | 10 +-
.../java/m1graphs2025/UndirectedGraph.java | 196 +++++++++++++++---
src/main/resources/isolatedNodes.gv | 8 +
src/main/resources/multiGraph.gv | 18 ++
src/main/resources/simpleGraph.gv | 12 ++
.../undirWeightedMultiGraph.gv | 0
src/main/resources/weightedMultiGraph.gv | 18 ++
src/main/resources/weightedSimpleGraph.gv | 12 ++
.../java/m1graphs2025/TestGraphPart1.java | 183 ++++++++++++++++
.../java/m1graphs2025/TestGraphPart2.java | 58 ++++++
.../java/m1graphs2025/TestGraphPart3.java | 50 +++++
.../java/m1graphs2025/TestGraphPart4.java | 111 ++++++++++
.../java/m1graphs2025/TestGraphPart5.java | 71 +++++++
15 files changed, 780 insertions(+), 68 deletions(-)
create mode 100644 src/main/resources/isolatedNodes.gv
create mode 100644 src/main/resources/multiGraph.gv
create mode 100644 src/main/resources/simpleGraph.gv
rename src/main/{java/m1graphs2025 => resources}/undirWeightedMultiGraph.gv (100%)
create mode 100644 src/main/resources/weightedMultiGraph.gv
create mode 100644 src/main/resources/weightedSimpleGraph.gv
create mode 100644 src/test/java/m1graphs2025/TestGraphPart1.java
create mode 100644 src/test/java/m1graphs2025/TestGraphPart2.java
create mode 100644 src/test/java/m1graphs2025/TestGraphPart3.java
create mode 100644 src/test/java/m1graphs2025/TestGraphPart4.java
create mode 100644 src/test/java/m1graphs2025/TestGraphPart5.java
diff --git a/src/main/java/m1graphs2025/Edge.java b/src/main/java/m1graphs2025/Edge.java
index 14ef5e0..0527c3d 100644
--- a/src/main/java/m1graphs2025/Edge.java
+++ b/src/main/java/m1graphs2025/Edge.java
@@ -134,7 +134,7 @@ public class Edge implements Comparable {
/**
* Retourne une arête symétrique (inversée) avec la même pondération.
- *
+ *
* @return une nouvelle arête inversée ou null si les nœuds n’appartiennent pas
* au même graphe.
*/
diff --git a/src/main/java/m1graphs2025/Graph.java b/src/main/java/m1graphs2025/Graph.java
index f565262..614a37e 100644
--- a/src/main/java/m1graphs2025/Graph.java
+++ b/src/main/java/m1graphs2025/Graph.java
@@ -928,7 +928,7 @@ public class Graph {
// ======================
public List getDFSWithVisitInfo(Map nodeVisit,
- Map edgeVisit) {
+ Map edgeVisit) {
List visited = new ArrayList<>();
AtomicInteger time = new AtomicInteger(0);
initVisitInfo(nodeVisit);
@@ -940,8 +940,8 @@ public class Graph {
}
public List getDFSWithVisitInfo(Node start,
- Map nodeVisit,
- Map edgeVisit) {
+ Map nodeVisit,
+ Map edgeVisit) {
List visited = new ArrayList<>();
AtomicInteger time = new AtomicInteger(0);
initVisitInfo(nodeVisit);
@@ -950,9 +950,9 @@ public class Graph {
}
private void DFSVisitEnriched(Node u, AtomicInteger time,
- Map nodeVisit,
- Map edgeVisit,
- List visited) {
+ Map nodeVisit,
+ Map edgeVisit,
+ List visited) {
time.incrementAndGet();
nodeVisit.get(u).setDiscoveryTime(time.get());
nodeVisit.get(u).setColour(NodeColour.GRAY);
@@ -984,49 +984,86 @@ public class Graph {
// ======================
public static Graph fromDotFile(String filename) {
- BufferedReader dot = new BufferedReader(new FileReader(filename));
Map> adjEdList = new HashMap<>();
Graph g = new Graph(adjEdList);
- BufferedReader dot = new BufferedReader(new FileReader(filename));
- List nodes = new ArrayList<>();
-
- String line = dot.readLine();
- while (line != null) {
- int iteration = 0;
- Edge edge = new Edge();
- Node nFrom = new Node();
- Node nTo = new Node();
- String[] tokens = line.split("[^0-9]");
- if (!tokens[0].equals("")) {
- if (!nodes.contains(Integer.parseInt(tokens[0]))) {
- List listEdges = new ArrayList<>();
- }
- nFrom.setId(Integer.parseInt(tokens[0]));
- edge.setNodeFrom(nFrom);
- nTo.setId(Integer.parseInt(tokens[1]));
- edge.setNodeTo(nTo);
- if (tokens[2] != "") {
- edge.setWeight(Integer.parseInt(tokens[2]));
+
+ try (BufferedReader dot = new BufferedReader(new FileReader(filename))) {
+ String line;
+
+ while ((line = dot.readLine()) != null) {
+ line = line.trim();
+ if (line.isEmpty()) continue; // ignore lignes vides
+
+ // Cas 1 : Ligne contenant seulement un numéro → nœud isolé
+ if (line.matches("^\\d+$")) {
+ int id = Integer.parseInt(line);
+ Node isolated = new Node(id, g, "");
+ adjEdList.putIfAbsent(isolated, new ArrayList<>());
+ continue;
}
- }
+ // Cas 2 : Ligne décrivant une arête, ex: "1 ------> 5 ----> 5"
+ String[] tokens = line.split("[^0-9]+");
+ if (tokens.length < 3) continue; // ligne invalide → on saute
+
+ int fromId = Integer.parseInt(tokens[0]);
+ int toId = Integer.parseInt(tokens[1]);
+ int weight = Integer.parseInt(tokens[2]);
+ Node nFrom = new Node(fromId, g, "");
+ Node nTo = new Node(toId, g, "");
+ Edge edge = new Edge(nFrom, nTo, weight);
+
+ // Ajout de l’arête dans la liste d’adjacence
+ adjEdList.computeIfAbsent(nFrom, k -> new ArrayList<>()).add(edge);
+
+ // S’assurer que le nœud destination existe
+ adjEdList.putIfAbsent(nTo, new ArrayList<>());
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Erreur lors de la lecture du fichier : " + filename, e);
}
+
+ return g;
}
+
public String toDotString() {
StringBuilder sb = new StringBuilder();
sb.append("digraph G {\n");
+ sb.append("\trankdir=LR;\n");
+
+ // Liste triée des arêtes
List edges = getAllEdges();
edges.sort(Comparator.comparingInt((Edge e) -> e.getNodeFrom().getId())
.thenComparingInt(e -> e.getNodeTo().getId()));
+
+ // Affichage des arêtes
for (Edge e : edges) {
- sb.append(e.getNodeFrom().getId()).append(" -> ").append(e.getNodeTo().getId());
+ sb.append("\t")
+ .append(e.getNodeFrom().getId())
+ .append(" -> ")
+ .append(e.getNodeTo().getId());
if (e.isWeighted()) {
- sb.append(" [label=").append(e.getWeight()).append(", len=").append(e.getWeight()).append("]");
+ sb.append(" [label=").append(e.getWeight())
+ .append(", len=").append(e.getWeight()).append("]");
}
- sb.append("\n");
+ sb.append(";\n");
}
+
+ // Affichage des nœuds isolés (ceux qui n’ont aucune arête)
+ Set nodesWithEdges = new HashSet<>();
+ for (Edge e : edges) {
+ nodesWithEdges.add(e.getNodeFrom());
+ nodesWithEdges.add(e.getNodeTo());
+ }
+
+ for (Node node : adjEdList.keySet()) {
+ if (!nodesWithEdges.contains(node)) {
+ sb.append("\t").append(node.getId()).append(";\n");
+ }
+ }
+
sb.append("}\n");
return sb.toString();
}
diff --git a/src/main/java/m1graphs2025/TestGraphsPW2.java b/src/main/java/m1graphs2025/TestGraphsPW2.java
index 6f9fb9b..96a9d7c 100644
--- a/src/main/java/m1graphs2025/TestGraphsPW2.java
+++ b/src/main/java/m1graphs2025/TestGraphsPW2.java
@@ -1,4 +1,4 @@
-package m1graphs2025;
+/**package m1graphs2025;
import java.util.Arrays;
import java.util.Collections;
@@ -407,8 +407,8 @@ public class TestGraphsPW2 {
* );
* System.out.println(
* "*-----------------------------------------------------------------------*");
- *
- *
+ *
+ *
* // lecture example but undirected
* UndirectedGraph gToVisit = new UndirectedGraph(
* 2, 3, 4, 6, 0, //1
@@ -424,6 +424,6 @@ public class TestGraphsPW2 {
* System.out.println(gToVisit.toDotString());
*/
- }
+ /**}
-}
+}**/
diff --git a/src/main/java/m1graphs2025/UndirectedGraph.java b/src/main/java/m1graphs2025/UndirectedGraph.java
index 595e22f..45ac02e 100644
--- a/src/main/java/m1graphs2025/UndirectedGraph.java
+++ b/src/main/java/m1graphs2025/UndirectedGraph.java
@@ -1,5 +1,11 @@
package m1graphs2025;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.*;
/**
@@ -20,12 +26,60 @@ public class UndirectedGraph extends Graph {
}
public UndirectedGraph(int... successorArray) {
- super(successorArray);
- // Ici, successorArray est interprété comme orienté,
- // donc on doit symétriser après construction
- symmetrize();
+ int taille = successorArray.length;
+ Map> adjEdList = new HashMap<>();
+ int i = 0;
+ int id = 1;
+
+ // D'abord, on crée tous les nœuds pour les réutiliser (sinon on crée des doublons)
+ Map nodes = new HashMap<>();
+
+ // Première passe : créer les nœuds
+ int tempId = 1;
+ while (i < taille) {
+ Node node = new Node(tempId, this);
+ nodes.put(tempId, node);
+
+ while (i < taille && successorArray[i] != 0) {
+ int succ = successorArray[i];
+ if (!nodes.containsKey(succ)) {
+ nodes.put(succ, new Node(succ, this));
+ }
+ i++;
+ }
+
+ i++; // sauter le 0
+ tempId++;
+ }
+
+ // Deuxième passe : créer les arêtes bidirectionnelles
+ i = 0;
+ id = 1;
+ while (i < taille) {
+ Node node = nodes.get(id);
+ List list = adjEdList.computeIfAbsent(node, k -> new ArrayList<>());
+
+ while (i < taille && successorArray[i] != 0) {
+ Node nodeTo = nodes.get(successorArray[i]);
+ Edge edge = new Edge(node, nodeTo);
+ list.add(edge);
+
+ // Ajout de l’arête inverse (bidirectionnelle)
+ List reverseList = adjEdList.computeIfAbsent(nodeTo, k -> new ArrayList<>());
+ Edge reverseEdge = new Edge(nodeTo, node);
+ reverseList.add(reverseEdge);
+
+ i++;
+ }
+
+ i++; // sauter le 0
+ id++;
+ }
+
+ this.adjEdList = adjEdList;
}
+
@Override
public boolean addNode(Node n) {
return super.addNode(n);
@@ -55,39 +109,32 @@ public class UndirectedGraph extends Graph {
@Override
public void addEdge(Node from, Node to) {
- super.addEdge(from, to);
- // Ajout symétrique
- if (!existsEdge(to, from))
- super.addEdge(to, from);
- }
-
- @Override
- public void addEdge(int fromId, int toId) {
- super.addEdge(fromId, toId);
- if (!existsEdge(toId, fromId))
- super.addEdge(toId, fromId);
+ super.addEdge(from, to); // u -> v
+ super.addEdge(to, from); // v -> u pour non dirigé
}
@Override
public void addEdge(Node from, Node to, int weight) {
super.addEdge(from, to, weight);
- if (!existsEdge(to, from))
- super.addEdge(to, from, weight);
+ super.addEdge(to, from, weight);
}
@Override
- public void addEdge(int fromId, int toId, int weight) {
- super.addEdge(fromId, toId, weight);
- if (!existsEdge(toId, fromId))
- super.addEdge(toId, fromId, weight);
+ public void addEdge(int fromId, int toId) {
+ Node from = getNode(fromId);
+ Node to = getNode(toId);
+ if (from == null) from = new Node(fromId, this);
+ if (to == null) to = new Node(toId, this);
+ addEdge(from, to);
}
@Override
- public void addEdge(Edge e) {
- super.addEdge(e);
- Edge sym = e.getSymmetric();
- if (sym != null && existsEdge(sym))
- super.addEdge(sym);
+ public void addEdge(int fromId, int toId, int weight) {
+ Node from = getNode(fromId);
+ Node to = getNode(toId);
+ if (from == null) from = new Node(fromId, this);
+ if (to == null) to = new Node(toId, this);
+ addEdge(from, to, weight);
}
@Override
@@ -114,13 +161,12 @@ public class UndirectedGraph extends Graph {
@Override
public boolean existsEdge(Node u, Node v) {
- // Pour un graphe non orienté, (u,v) == (v,u)
return super.existsEdge(u, v) || super.existsEdge(v, u);
}
@Override
- public boolean existsEdge(Edge e) {
- return super.existsEdge(e);
+ public boolean existsEdge(int uId, int vId) {
+ return existsEdge(getNode(uId), getNode(vId));
}
@Override
@@ -159,8 +205,96 @@ public class UndirectedGraph extends Graph {
return closure;
}
- public static UndirectedGraph fromDotFile(String filename) {
- return fromDotFile(filename, ".gv");
+ public static Graph fromDotFile(String filename) {
+ Map> adjEdList = new HashMap<>();
+ Graph g = new UndirectedGraph(adjEdList);
+
+ try (BufferedReader dot = new BufferedReader(new FileReader(filename))) {
+ String line;
+
+ while ((line = dot.readLine()) != null) {
+ line = line.trim();
+ if (line.isEmpty()) continue; // ignore lignes vides
+
+ // Cas 1 : Ligne contenant seulement un numéro → nœud isolé
+ if (line.matches("^\\d+$")) {
+ int id = Integer.parseInt(line);
+ Node isolated = new Node(id, g, "");
+ adjEdList.putIfAbsent(isolated, new ArrayList<>());
+ continue;
+ }
+
+ // Cas 2 : Ligne décrivant une arête, ex: "1 ------> 5 ----> 5"
+ String[] tokens = line.split("[^0-9]+");
+ if (tokens.length < 3) continue; // ligne invalide → on saute
+
+ int fromId = Integer.parseInt(tokens[0]);
+ int toId = Integer.parseInt(tokens[1]);
+ int weight = Integer.parseInt(tokens[2]);
+
+ Node nFrom = new Node(fromId, g, "");
+ Node nTo = new Node(toId, g, "");
+ Edge edge = new Edge(nFrom, nTo, weight);
+
+ // Ajout de l’arête dans la liste d’adjacence
+ adjEdList.computeIfAbsent(nFrom, k -> new ArrayList<>()).add(edge);
+
+ // S’assurer que le nœud destination existe
+ adjEdList.putIfAbsent(nTo, new ArrayList<>());
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Erreur lors de la lecture du fichier : " + filename, e);
+ }
+
+ return g;
+ }
+
+ public String toDotString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("graph G {\n");
+ sb.append("\trankdir=LR\n");
+
+ // Liste triée des arêtes
+ List edges = getAllEdges();
+ edges.sort(Comparator.comparingInt((Edge e) -> e.getNodeFrom().getId())
+ .thenComparingInt(e -> e.getNodeTo().getId()));
+
+ // Affichage des arêtes
+ for (Edge e : edges) {
+ sb.append("\t")
+ .append(e.getNodeFrom().getId())
+ .append(" -- ")
+ .append(e.getNodeTo().getId());
+ if (e.isWeighted()) {
+ sb.append(" [label=").append(e.getWeight())
+ .append(", len=").append(e.getWeight()).append("]");
+ }
+ sb.append(";\n");
+ }
+
+ // Affichage des nœuds isolés (ceux qui n’ont aucune arête)
+ Set nodesWithEdges = new HashSet<>();
+ for (Edge e : edges) {
+ nodesWithEdges.add(e.getNodeFrom());
+ nodesWithEdges.add(e.getNodeTo());
+ }
+
+ for (Node node : adjEdList.keySet()) {
+ if (!nodesWithEdges.contains(node)) {
+ sb.append("\t").append(node.getId()).append(";\n");
+ }
+ }
+
+ sb.append("}\n");
+ return sb.toString();
+ }
+
+ public void toDotFile(String filename) {
+ super.toDotFile(filename);
+ }
+
+ public void toDotFile(String filename, String ext) {
+ super.toDotFile(filename, ".gv");
}
// ======================
diff --git a/src/main/resources/isolatedNodes.gv b/src/main/resources/isolatedNodes.gv
new file mode 100644
index 0000000..221faf2
--- /dev/null
+++ b/src/main/resources/isolatedNodes.gv
@@ -0,0 +1,8 @@
+digraph {
+ rankdir=LR
+ 1
+ 2 -> 3
+ 4
+ 5
+ 8
+}
\ No newline at end of file
diff --git a/src/main/resources/multiGraph.gv b/src/main/resources/multiGraph.gv
new file mode 100644
index 0000000..d4bec97
--- /dev/null
+++ b/src/main/resources/multiGraph.gv
@@ -0,0 +1,18 @@
+digraph {
+ rankdir=LR
+ 1 -> 2
+ 2 -> 3
+ 2 -> 4
+ 2 -> 4
+ 2 -> 5
+ 3 -> 1
+ 3 -> 1
+ 3 -> 5
+ 4 -> 1
+ 4 -> 4
+ 4 -> 5
+ 6 -> 5
+ 6 -> 5
+ 6 -> 6
+ 6 -> 6
+}
\ No newline at end of file
diff --git a/src/main/resources/simpleGraph.gv b/src/main/resources/simpleGraph.gv
new file mode 100644
index 0000000..9658c6d
--- /dev/null
+++ b/src/main/resources/simpleGraph.gv
@@ -0,0 +1,12 @@
+digraph {
+ rankdir=LR
+ 1 -> 2
+ 2 -> 3
+ 2 -> 4
+ 2 -> 5
+ 3 -> 1
+ 3 -> 5
+ 4 -> 1
+ 4 -> 5
+ 6 -> 5
+}
\ No newline at end of file
diff --git a/src/main/java/m1graphs2025/undirWeightedMultiGraph.gv b/src/main/resources/undirWeightedMultiGraph.gv
similarity index 100%
rename from src/main/java/m1graphs2025/undirWeightedMultiGraph.gv
rename to src/main/resources/undirWeightedMultiGraph.gv
diff --git a/src/main/resources/weightedMultiGraph.gv b/src/main/resources/weightedMultiGraph.gv
new file mode 100644
index 0000000..5ef48fd
--- /dev/null
+++ b/src/main/resources/weightedMultiGraph.gv
@@ -0,0 +1,18 @@
+digraph {
+ rankdir=LR
+ 1 -> 2 [label=4, len=4]
+ 2 -> 3 [label=1, len=1]
+ 2 -> 4 [label=2, len=2]
+ 2 -> 4 [label=50, len=50]
+ 2 -> 5 [label=3, len=3]
+ 3 -> 1 [label=3, len=3]
+ 3 -> 1 [label=6, len=6]
+ 3 -> 5 [label=2, len=2]
+ 4 -> 1 [label=0, len=0]
+ 4 -> 4 [label=14, len=14]
+ 4 -> 5 [label=2, len=2]
+ 6 -> 5 [label=7, len=7]
+ 6 -> 5 [label=10, len=10]
+ 6 -> 6 [label=5, len=5]
+ 6 -> 6 [label=8, len=8]
+}
\ No newline at end of file
diff --git a/src/main/resources/weightedSimpleGraph.gv b/src/main/resources/weightedSimpleGraph.gv
new file mode 100644
index 0000000..c305506
--- /dev/null
+++ b/src/main/resources/weightedSimpleGraph.gv
@@ -0,0 +1,12 @@
+digraph {
+ rankdir=LR
+ 1 -> 2 [label=4, len=4]
+ 2 -> 3 [label=1, len=1]
+ 2 -> 4 [label=2, len=2]
+ 2 -> 5 [label=3, len=3]
+ 3 -> 1 [label=6, len=6]
+ 3 -> 5 [label=2, len=2]
+ 4 -> 1 [label=0, len=0]
+ 4 -> 5 [label=2, len=2]
+ 6 -> 5 [label=7, len=7]
+}
\ No newline at end of file
diff --git a/src/test/java/m1graphs2025/TestGraphPart1.java b/src/test/java/m1graphs2025/TestGraphPart1.java
new file mode 100644
index 0000000..b2d8bb0
--- /dev/null
+++ b/src/test/java/m1graphs2025/TestGraphPart1.java
@@ -0,0 +1,183 @@
+package m1graphs2025;
+
+import java.util.Collections;
+import java.util.List;
+
+public class TestGraphPart1 {
+
+ public static void main(String[] args) {
+ System.out.println("*--------------------------------------------------------------------*");
+ System.out.println("************ PART 1. UNWEIGTED DIRECTED GRAPHS ***********************");
+ System.out.println("*--------------------------------------------------------------------*");
+ System.out.println("\n>>>>>>>> SIMPLE GRAPH >>>>>>>>>>>>>>>>>>>>>>>>");
+ System.out.println(">>>>>>>> Creating the subject example graph in G");
+ Graph g = new Graph(2, 4, 0, 0, 6, 0, 2, 3, 5, 8, 0, 0, 4, 7, 0, 3, 0, 7, 0);
+ System.out.println(">>>> Graph information");
+ System.out.println(">> DOT representation\n" + g.toDotString());
+ System.out.println("" + g.nbNodes() + " nodes, " + g.nbEdges() + " edges");
+ System.out.println(">> Nodes: ");
+ List nodes = g.getAllNodes();
+ Collections.sort(nodes);
+ for (Node n : nodes)
+ System.out.println("Node " + n + ": degree " + g.degree(n) + " (in: " + g.inDegree(n) + "/ out: "
+ + g.outDegree(n) + ")");
+
+ List edges;
+ System.out.println(">> Edges: ");
+ System.out.println("---------------------------");
+ System.out.println("Out-edges per node");
+ for (Node n : nodes) {
+ edges = g.getOutEdges(n);
+ Collections.sort(edges);
+ System.out.println("" + n + ": " + edges);
+ }
+
+ System.out.println("In-edges per node");
+ for (Node n : nodes) {
+ edges = g.getInEdges(n);
+ Collections.sort(edges);
+ System.out.println("" + n + ": " + edges);
+ }
+
+ /////////////////////////////////////////////////////
+
+ System.out.println("\n>>>>>>>> creating isolated node 12");
+ if (!g.addNode(12))
+ System.out.println("Error: failed to create node 12");
+ System.out.println("Graph now:");
+ System.out.println(g.toDotString());
+ System.out.println("" + g.nbNodes() + " nodes, " + g.nbEdges() + " edges");
+ nodes = g.getAllNodes();
+ Collections.sort(nodes);
+ System.out.println("Nodes list: " + nodes);
+
+ System.out.println("\n>>>>>>>> Removing node 3");
+ g.removeNode(3);
+ System.out.println("Graph now:");
+ System.out.println(g.toDotString());
+ System.out.println("" + g.nbNodes() + " nodes, " + g.nbEdges() + " edges");
+ nodes = g.getAllNodes();
+ Collections.sort(nodes);
+ System.out.println("Nodes list: " + nodes);
+
+ System.out.println(">> Edges: ");
+ System.out.println("---------------------------");
+ System.out.println("Out-edges per node");
+ for (Node n : nodes) {
+ edges = g.getOutEdges(n);
+ Collections.sort(edges);
+ System.out.println("" + n + ": " + edges);
+ }
+
+ System.out.println("In-edges per node");
+ for (Node n : nodes) {
+ edges = g.getInEdges(n);
+ Collections.sort(edges);
+ System.out.println("" + n + ": " + edges);
+ }
+
+ System.out.println(
+ "\n>>>>>>>> Recreating edges (4, 3), (3, 6), (7, 3), adding edge (12, 3), creating edge (3, 25)");
+ g.addEdge(new Edge(4, 3, g));
+ g.addEdge(new Edge(3, 6, g));
+ g.addEdge(new Edge(7, 3, g));
+ g.addEdge(new Edge(12, 3, g));
+ g.addEdge(3, 25);
+ System.out.println("Graph now:");
+ System.out.println(g.toDotString());
+ System.out.println("" + g.nbNodes() + " nodes, " + g.nbEdges() + " edges");
+ nodes = g.getAllNodes();
+ Collections.sort(nodes);
+ System.out.println("Nodes list: " + nodes);
+
+ System.out.println("");
+ System.out.println("\n>>>>>>>> Edges removal");
+ System.out.println(">>>> Removing existing edges (7, 3) and (4, 8)");
+ g.removeEdge(7, 3);
+ g.removeEdge(4, 8);
+ System.out.println(">>>> Removing absent edge (3, 4)");
+ g.removeEdge(3, 4);
+ System.out.println(
+ ">>>> Removing edges whith 1 or 2 not existing end-points: (-3, 4), (6, 0), (4, 11), (-1, -2), (13, 3), (9, 10)");
+ g.removeEdge(-3, 4);
+ g.removeEdge(6, 0);
+ g.removeEdge(4, 11);
+ g.removeEdge(-1, -2);
+ g.removeEdge(13, 3);
+ g.removeEdge(9, 10);
+
+ System.out.println("Graph now:");
+ System.out.println(g.toDotString());
+ System.out.println("" + g.nbNodes() + " nodes, " + g.nbEdges() + " edges");
+ nodes = g.getAllNodes();
+ Collections.sort(nodes);
+ System.out.println("Nodes list: " + nodes);
+
+ System.out.println(
+ "\nTesting that getSuccessors and getSuccessorsMulti give the same result for the simple graph:");
+ boolean same = true;
+ for (Node u : nodes) {
+ List succs = g.getSuccessors(u), succsMulti = g.getSuccessorsMulti(u);
+ // sort the lists so that nodes always appear in the same order
+ Collections.sort(succs);
+ Collections.sort(succsMulti);
+ same = same && succs.equals(succsMulti);
+ }
+ System.out.println("\tgetSuccessors and getSuccessorsMulti " + (same ? "are identical" : "differ"));
+
+ System.out.println("\n>>>>>>>> MULTIGRAPH: adding a self-loop on node 6, and a second edge (1, 4)");
+ g.addEdge(6, 6);
+ g.addEdge(1, 4);
+ System.out.println("Graph now:");
+ System.out.println(g.toDotString());
+ System.out.println("" + g.nbNodes() + " nodes, " + g.nbEdges() + " edges");
+ nodes = g.getAllNodes();
+ Collections.sort(nodes);
+ System.out.println("Nodes list: " + nodes);
+ System.out.println(
+ "Degree of node 6: " + g.degree(6) + " (in: " + g.inDegree(6) + "/ out: " + g.outDegree(6) + ")");
+
+ System.out.println(">> Edges: ");
+ System.out.println("---------------------------");
+ System.out.println("Out-edges per node");
+ for (Node n : nodes) {
+ edges = g.getOutEdges(n);
+ Collections.sort(edges);
+ System.out.println("" + n + ": " + edges);
+ }
+
+ System.out.println("In-edges per node");
+ for (Node n : nodes) {
+ edges = g.getInEdges(n);
+ Collections.sort(edges);
+ System.out.println("" + n + ": " + edges);
+ }
+
+ System.out.println("\n>>>>>>>>>> Get the reverse graph");
+ System.out.println(g.getReverse().toDotString());
+
+ System.out.println(">>>>>>>>>> Get the transitive closure");
+ System.out.println(g.getTransitiveClosure().toDotString());
+
+ System.out.println(">>>>>>>>>> Emptying the graph by removing all its nodes");
+ nodes = g.getAllNodes();
+ for (Node u : nodes)
+ g.removeNode(u);
+ System.out.println("Graph now:");
+ System.out.println(g.toDotString());
+
+ System.out.println(">>>> Searching for node 7:");
+ if (g.usesNode(7))
+ System.out.println("\tNode 7 exists");
+ else
+ System.out.println("\tThere is no Node 7");
+
+ System.out.println(">>>> Searching for edge (4, 2):");
+ if (g.existsEdge(4, 2))
+ System.out.println("\tEdge (4, 2) exists");
+ else
+ System.out.println("\tThere is no edge (4, 2)");
+
+ System.out.println();
+ }
+}
diff --git a/src/test/java/m1graphs2025/TestGraphPart2.java b/src/test/java/m1graphs2025/TestGraphPart2.java
new file mode 100644
index 0000000..d764977
--- /dev/null
+++ b/src/test/java/m1graphs2025/TestGraphPart2.java
@@ -0,0 +1,58 @@
+package m1graphs2025;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class TestGraphPart2 {
+
+ public static void main(String[] args) {
+ System.out.println("*------------------------------------------------------------------*");
+ System.out.println("********* PART 2. READING GRAPHS FROM DOT FILES ****************");
+ System.out.println("*------------------------------------------------------------------*");
+ System.out.println("\n>>> Graph with isolated nodes: reading file 'isolatedNodes.gv'");
+ Graph gin = Graph.fromDotFile("src/main/resources/isolatedNodes.gv");
+ if (gin == null)
+ System.out.println("Null graph was created from 'isolatedNodes.gv'");
+ else {
+ System.out.println("Read: OK. The graph with isolated nodes has been read as:");
+ System.out.println("---------------------");
+ System.out.println(gin.toDotString());
+ System.out.println("---------------------");
+ }
+
+ System.out.println(">>> Simple graph: reading file 'simpleGraph.gv'");
+ Graph sg = Graph.fromDotFile("src/main/resources/simpleGraph.gv");
+ if (sg == null)
+ System.out.println("Null graph was created from 'simpleGraph.gv'");
+ else {
+ System.out.println("Read: OK. The simple graph has been read as:");
+ System.out.println("---------------------");
+ System.out.println(sg.toDotString());
+ System.out.println("---------------------");
+ }
+
+ System.out.println("\n>>> Multi-graph: reading file 'multiGraph.gv'");
+ Graph mg = Graph.fromDotFile("src/main/resources/multiGraph.gv");
+ if (mg == null)
+ System.out.println("Null graph was created from 'multiGraph.gv'");
+ else {
+ System.out.println("Read: OK. The multi-graph has been read as:");
+ System.out.println("---------------------");
+ System.out.println(mg.toDotString());
+ System.out.println("---------------------");
+ }
+
+ System.out.println("Comparing single and multi successors per node for 'multiGraph.gv'");
+ for (Node u : mg.getAllNodes()) {
+ List succs = mg.getSuccessors(u), succsMulti = mg.getSuccessorsMulti(u);
+ // sort the lists so that nodes always appear in the same order
+ Collections.sort(succs);
+ Collections.sort(succsMulti);
+ System.out.println("" + u + " single successors: " + succs);
+ System.out.println("" + u + " multi successors: " + succsMulti);
+ }
+
+ System.out.println("\n\n");
+ }
+}
diff --git a/src/test/java/m1graphs2025/TestGraphPart3.java b/src/test/java/m1graphs2025/TestGraphPart3.java
new file mode 100644
index 0000000..84ed56a
--- /dev/null
+++ b/src/test/java/m1graphs2025/TestGraphPart3.java
@@ -0,0 +1,50 @@
+package m1graphs2025;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class TestGraphPart3 {
+
+ public static void main(String[] args) {
+ System.out.println("*----------------------------------------------------------------------*");
+ System.out.println("************* PART 3. WEIGHTED DIRECTED GRAPHS ***********************");
+ System.out.println("*----------------------------------------------------------------------*");
+ int totalEdgesWeight = 0;
+
+ System.out.println("\n>>>>>>>>>>");
+ System.out.println("Reading a weighted directed simple graph from DOT file 'weightedSimpleGraph.gv'");
+ Graph wsg = Graph.fromDotFile("src/main/resources/weightedSimpleGraph.gv");
+ if (wsg == null)
+ System.out.println("Null graph was created from 'weightedSimpleGraph.gv'");
+ else {
+ System.out.println("Read: OK. The weighted directed simple graph has been read as:");
+ System.out.println("---------------------");
+ System.out.println(wsg.toDotString());
+ System.out.println("---------------------");
+
+ for (Edge e : wsg.getAllEdges())
+ totalEdgesWeight += e.getWeight();
+ System.out.println("The sum of all edges weights equals " + totalEdgesWeight);
+ }
+
+ System.out.println("\n>>>>>>>>>>");
+ System.out.println("Reading a weighted directed multi graph from DOT file 'weightedMultiGraph.gv'");
+ Graph wmg = Graph.fromDotFile("src/main/resources/weightedMultiGraph.gv");
+ if (wmg == null)
+ System.out.println("Null graph was created from 'weightedMultiGraph.gv'");
+ else {
+ System.out.println("Read: OK. The weighted directed multi graph has been read as:");
+ System.out.println("---------------------");
+ System.out.println(wmg.toDotString());
+ System.out.println("---------------------");
+
+ totalEdgesWeight = 0;
+ for (Edge e : wmg.getAllEdges())
+ totalEdgesWeight += e.getWeight();
+ System.out.println("The sum of all edges weights equals " + totalEdgesWeight);
+ }
+
+ System.out.println("\n\n");
+ }
+}
diff --git a/src/test/java/m1graphs2025/TestGraphPart4.java b/src/test/java/m1graphs2025/TestGraphPart4.java
new file mode 100644
index 0000000..7200435
--- /dev/null
+++ b/src/test/java/m1graphs2025/TestGraphPart4.java
@@ -0,0 +1,111 @@
+package m1graphs2025;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class TestGraphPart4 {
+
+ public static void main(String[] args) {
+
+ System.out.println("*-------------------------------------------------------------------------*");
+ System.out.println("************ PART 4. UNDIRECTED UNWEIGHTED GRAPHS ***********************");
+ System.out.println("*-------------------------------------------------------------------------*");
+
+ System.out.println("\nCreating an undirected simple graph 'usg' from scracth");
+ UndirectedGraph usg = new UndirectedGraph(2, 3, 0, 3, 4, 0, 4, 0, 0);
+ System.out.println(usg.toDotString());
+ System.out.println("usg has " + usg.nbNodes() + " nodes and " + usg.nbEdges() + " edges.");
+
+ System.out.println("\n>>>>>> usg: Counting degrees and showing successors");
+ for (Node u : usg.getAllNodes()) {
+ System.out.println("Node " + u + ". Degree: " + usg.degree(u.getId()) + " (In: " + usg.inDegree(u.getId())
+ + " / Out: " + usg.outDegree(u.getId()) + ")");
+ System.out.println("\tSuccessors: " + usg.getSuccessors(u));
+ }
+
+ System.out.println(">>>>>> usg: Edges of the graph");
+ System.out.println("// N.B. The edges are printed as though they were directed. This is due to the toString()\n"
+ + "// method that was not overridden. It is possible to do better but not important.\n"
+ + "// What is important is that each edge appears only once per direction.");
+ System.out.println("All edges of the graph: " + usg.getAllEdges());
+ System.out.println("Out-edges per node");
+ for (Node u : usg.getAllNodes())
+ System.out.println("" + u + ": " + usg.getOutEdges(u));
+ System.out.println("In-edges per node");
+ for (Node u : usg.getAllNodes())
+ System.out.println("" + u + ": " + usg.getInEdges(u));
+ System.out.println("Incident edges per node");
+ for (Node u : usg.getAllNodes())
+ System.out.println("" + u + ": " + usg.getIncidentEdges(u));
+
+ System.out.println("Creating an undirected multi-graph with self-loops 'umg' from scratch");
+ UndirectedGraph umg = new UndirectedGraph(1, 1, 2, 2, 3, 0, 2, 3, 0, 0);
+
+ String dotUMG = umg.toDotString();
+ System.out.println(dotUMG);
+ System.out.println("umg has " + umg.nbNodes() + " nodes and " + umg.nbEdges() + " edges.");
+
+ System.out.println("\n>>>>>> umg: Counting degrees and showing successors");
+ for (Node u : umg.getAllNodes()) {
+ System.out.println("Node " + u + ". Degree: " + umg.degree(u.getId()) + " (In: " + umg.inDegree(u.getId())
+ + " / Out: " + umg.outDegree(u.getId()) + ")");
+ System.out.println("\tSuccessors: " + umg.getSuccessors(u));
+ }
+
+ System.out.println(">>>>>> umg: Edges of the graph");
+ System.out.println("All edges of the graph: " + umg.getAllEdges());
+ System.out.println("Out-edges per node");
+ for (Node u : umg.getAllNodes())
+ System.out.println("" + u + ": " + umg.getOutEdges(u));
+ System.out.println("In-edges per node");
+ for (Node u : umg.getAllNodes())
+ System.out.println("" + u + ": " + umg.getInEdges(u));
+ System.out.println("Incident edges per node");
+ for (Node u : umg.getAllNodes())
+ System.out.println("" + u + ": " + umg.getIncidentEdges(u));
+
+ System.out.println("\n>>>>>> umg: Successor Array, Adjacency Matrix, and Graph Reverse");
+ System.out.println("umg Successor array\n" + Arrays.toString(umg.toSuccessorArray()));
+
+ System.out.println("umg Adjacency Matrix");
+ for (int[] row : umg.toAdjMatrix())
+ System.out.println("\t" + Arrays.toString(row));
+
+ System.out.println("Testing via toDotString() the equality with the reverse graph");
+ String dotRUMG = umg.getReverse().toDotString();
+ System.out.println("DOT of the reverse of umg\n" + dotRUMG);
+ System.out.println("Graph gu and its reverse " + (dotUMG.equals(dotRUMG) ? "are identical" : "differ"));
+
+ System.out.println("-----------------\n NOW a disconnected GRAPH \n----------------");
+ System.out.println("Building 'guDisc', a disconnected undirected graph with multi-edges and self-loops");
+ UndirectedGraph guDisc = new UndirectedGraph(1, 1, 2, 2, 6, 0, 2, 3, 6, 0, 0, 6, 0, 6, 0, 0, 0, 9, 10, 0, 0, 0);
+ System.out.println(guDisc.toDotString());
+
+ // delete
+ // Graph guDisc2 = new Graph(1,1,2,2,6,0, 2,3,6,0, 0, 6,0, 6,0, 0, 0, 9,10,0, 0,
+ // 0);
+ // System.out.println(guDisc2.toDotString());
+ // System.exit(0);
+ // end delete
+
+ System.out.println("Comparing single and multi successors per node for guDisc");
+ for (Node u : guDisc.getAllNodes()) {
+ List succs = guDisc.getSuccessors(u), succsMulti = guDisc.getSuccessorsMulti(u);
+ // sort the lists so that nodes always appear in the same order
+ Collections.sort(succs);
+ Collections.sort(succsMulti);
+ System.out.println("" + u + " single successors: " + succs);
+ System.out.println("" + u + " multi successors: " + succsMulti);
+ }
+
+ System.out.println(">>>> DFS of guDisc: " + guDisc.getDFS());
+ System.out.println(">>>> BFS of guDisc: " + guDisc.getBFS());
+
+ System.out.println(">>>>>>> Computing guDisc's transitive closure");
+ UndirectedGraph guDiscTC = (UndirectedGraph) guDisc.getTransitiveClosure();
+ System.out.println(guDiscTC.toDotString());
+
+ System.out.println("\n\n");
+ }
+}
diff --git a/src/test/java/m1graphs2025/TestGraphPart5.java b/src/test/java/m1graphs2025/TestGraphPart5.java
new file mode 100644
index 0000000..c9e4468
--- /dev/null
+++ b/src/test/java/m1graphs2025/TestGraphPart5.java
@@ -0,0 +1,71 @@
+package m1graphs2025;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class TestGraphPart5 {
+
+ public static void main(String[] args) {
+
+ System.out.println("*-----------------------------------------------------------------------*");
+ System.out.println("************ PART 5. UNDIRECTED WEIGHTED GRAPHS ***********************");
+ System.out.println("*-----------------------------------------------------------------------*");
+
+ System.out.println("\n>>>>>> Reading 'uwmg' an undirected weighted multi-graph with self loops\n"
+ + "from file 'undirWeightedMultiGraph.gv'");
+
+ UndirectedGraph uwmg = (UndirectedGraph) UndirectedGraph.fromDotFile("src/main/resources/undirWeightedMultiGraph.gv");
+ if (uwmg == null)
+ System.out.println("Null graph was created from 'undirWeightedMultiGraph.gv'");
+ else {
+ System.out.println("Read: OK. The undirected weighted multi-graph has been read as:");
+ System.out.println("---------------------");
+ System.out.println(uwmg.toDotString());
+ System.out.println("---------------------");
+
+ Integer totalEdgesWeight = 0;
+ for (Edge e : uwmg.getAllEdges())
+ totalEdgesWeight += e.getWeight();
+ System.out.println("The sum of all edges weights equals " + totalEdgesWeight);
+ }
+
+ System.out.println("\nComparing single and multi successors per node for uwmg");
+ for (Node u : uwmg.getAllNodes()) {
+ List succs = uwmg.getSuccessors(u), succsMulti = uwmg.getSuccessorsMulti(u);
+ // sort the lists so that nodes always appear in the same order
+ Collections.sort(succs);
+ Collections.sort(succsMulti);
+ System.out.println("" + u + " single successors: " + succs);
+ System.out.println("" + u + " multi successors: " + succsMulti);
+ }
+
+ /*
+ * TO BE CONTINUED ...
+ * System.out.println("\n\n");
+ * System.out.println(
+ * "*-----------------------------------------------------------------------*");
+ * System.out.
+ * println("************ PART 6. DFS and Node Visit Info ***********************"
+ * );
+ * System.out.println(
+ * "*-----------------------------------------------------------------------*");
+ *
+ *
+ * // lecture example but undirected
+ * UndirectedGraph gToVisit = new UndirectedGraph(
+ * 2, 3, 4, 6, 0, //1
+ * 5, 6, 0, //2
+ * 4, 0, //3
+ * 8, 0, //4
+ * 6, 7, 8, 0, //5
+ * 7, 0, //6
+ * 8,0, //7
+ * 0 //8
+ * );
+ * System.out.println("\nAn undirected graph to visit:");
+ * System.out.println(gToVisit.toDotString());
+ */
+
+ }
+}
--
GitLab
From bf6646e2568cd77bd0ed40e9192c9b0126eda6ae Mon Sep 17 00:00:00 2001
From: adjemaou
Date: Fri, 31 Oct 2025 22:05:04 +0100
Subject: [PATCH 3/3] fixing part2
---
src/main/java/m1graphs2025/Graph.java | 165 ++++++++++++------
.../java/m1graphs2025/UndirectedGraph.java | 6 +-
2 files changed, 111 insertions(+), 60 deletions(-)
diff --git a/src/main/java/m1graphs2025/Graph.java b/src/main/java/m1graphs2025/Graph.java
index 614a37e..a4bf39c 100644
--- a/src/main/java/m1graphs2025/Graph.java
+++ b/src/main/java/m1graphs2025/Graph.java
@@ -101,10 +101,14 @@ public class Graph {
if (entry != null && entry.getId() == id)
return entry;
}
- System.err.println("Aucun nœud trouvé avec l’id " + id + ".");
+
return null;
}
+ public Node getOrCreateNode(int id) {
+ return getNode(id) != null ? getNode(id) : new Node(id, this);
+ }
+
public boolean addNode(Node n) {
if (n == null) {
System.err.println("Erreur: tentative d’ajout d’un nœud null.");
@@ -928,7 +932,7 @@ public class Graph {
// ======================
public List getDFSWithVisitInfo(Map nodeVisit,
- Map edgeVisit) {
+ Map edgeVisit) {
List visited = new ArrayList<>();
AtomicInteger time = new AtomicInteger(0);
initVisitInfo(nodeVisit);
@@ -940,8 +944,8 @@ public class Graph {
}
public List getDFSWithVisitInfo(Node start,
- Map nodeVisit,
- Map edgeVisit) {
+ Map nodeVisit,
+ Map edgeVisit) {
List visited = new ArrayList<>();
AtomicInteger time = new AtomicInteger(0);
initVisitInfo(nodeVisit);
@@ -950,9 +954,9 @@ public class Graph {
}
private void DFSVisitEnriched(Node u, AtomicInteger time,
- Map nodeVisit,
- Map edgeVisit,
- List visited) {
+ Map nodeVisit,
+ Map edgeVisit,
+ List visited) {
time.incrementAndGet();
nodeVisit.get(u).setDiscoveryTime(time.get());
nodeVisit.get(u).setColour(NodeColour.GRAY);
@@ -983,88 +987,135 @@ public class Graph {
// DOT I/O
// ======================
+ /**
+ * Builds a {@link Graph} instance by parsing a DOT-like file.
+ *
+ * The expected format supports both isolated nodes and weighted edges.
+ * Examples of valid lines:
+ *
+ * 1 → an isolated node
+ * 1 -> 2 [label="5"]; → a directed edge with weight 5
+ * 1 -> 3; → a directed edge without weight (defaults to
+ * 1)
+ *
+ *
+ *
+ * @param filename the path to the DOT file to parse
+ * @return a new {@link Graph} built from the file contents
+ * @throws RuntimeException if the file cannot be read or parsed
+ */
+ /**
+ * Reads a directed graph from a DOT-like file.
+ * Supports lines such as:
+ * 1 -> 2 [label="5"];
+ * 3
+ * (isolated node)
+ *
+ * @param filename the path to the DOT file
+ * @return a Graph instance representing the file content
+ * @throws RuntimeException if file reading fails
+ */
public static Graph fromDotFile(String filename) {
Map> adjEdList = new HashMap<>();
Graph g = new Graph(adjEdList);
- try (BufferedReader dot = new BufferedReader(new FileReader(filename))) {
+ try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
String line;
- while ((line = dot.readLine()) != null) {
+ while ((line = reader.readLine()) != null) {
line = line.trim();
- if (line.isEmpty()) continue; // ignore lignes vides
+ if (line.isEmpty())
+ continue; // skip empty lines
- // Cas 1 : Ligne contenant seulement un numéro → nœud isolé
+ // --- Case 1: isolated node
if (line.matches("^\\d+$")) {
int id = Integer.parseInt(line);
- Node isolated = new Node(id, g, "");
- adjEdList.putIfAbsent(isolated, new ArrayList<>());
+ Node node = g.getOrCreateNode(id);
+ adjEdList.putIfAbsent(node, new ArrayList<>());
continue;
}
- // Cas 2 : Ligne décrivant une arête, ex: "1 ------> 5 ----> 5"
- String[] tokens = line.split("[^0-9]+");
- if (tokens.length < 3) continue; // ligne invalide → on saute
+ // --- Case 2: edge line
+ String[] tokens = line.replaceAll("[^0-9]+", " ").trim().split("\\s+");
+ if (tokens.length < 2)
+ continue; // invalid line → skip
int fromId = Integer.parseInt(tokens[0]);
- int toId = Integer.parseInt(tokens[1]);
- int weight = Integer.parseInt(tokens[2]);
+ int toId = Integer.parseInt(tokens[1]);
- Node nFrom = new Node(fromId, g, "");
- Node nTo = new Node(toId, g, "");
- Edge edge = new Edge(nFrom, nTo, weight);
+ Node from = g.getOrCreateNode(fromId);
+ Node to = g.getOrCreateNode(toId);
- // Ajout de l’arête dans la liste d’adjacence
- adjEdList.computeIfAbsent(nFrom, k -> new ArrayList<>()).add(edge);
+ Edge edge;
+ if (tokens.length >= 3) {
+ int weight = Integer.parseInt(tokens[2]);
+ edge = new Edge(from, to, weight);
+ } else {
+ edge = new Edge(from, to);
+ }
- // S’assurer que le nœud destination existe
- adjEdList.putIfAbsent(nTo, new ArrayList<>());
+ // Add to adjacency list
+ adjEdList.computeIfAbsent(from, k -> new ArrayList<>()).add(edge);
+ adjEdList.putIfAbsent(to, new ArrayList<>()); // ensure target node exists
}
+
} catch (IOException e) {
- throw new RuntimeException("Erreur lors de la lecture du fichier : " + filename, e);
+ throw new RuntimeException("Error reading file: " + filename, e);
}
return g;
}
-
+ /**
+ * Generates a DOT-format string representation of this graph.
+ *
+ * Example output for a directed graph:
+ *
+ *
+ * digraph G {
+ * rankdir=LR;
+ * 1 -> 2 [label="5"];
+ * 2 -> 3;
+ * 4;
+ * }
+ *
+ *
+ *
+ * @return the DOT-format representation of the graph
+ */
public String toDotString() {
+ boolean isDirected = true; // adapt this if you support undirected graphs
+ String arrow = isDirected ? " -> " : " -- ";
+
StringBuilder sb = new StringBuilder();
- sb.append("digraph G {\n");
- sb.append("\trankdir=LR;\n");
-
- // Liste triée des arêtes
- List edges = getAllEdges();
- edges.sort(Comparator.comparingInt((Edge e) -> e.getNodeFrom().getId())
- .thenComparingInt(e -> e.getNodeTo().getId()));
-
- // Affichage des arêtes
- for (Edge e : edges) {
- sb.append("\t")
- .append(e.getNodeFrom().getId())
- .append(" -> ")
- .append(e.getNodeTo().getId());
- if (e.isWeighted()) {
- sb.append(" [label=").append(e.getWeight())
- .append(", len=").append(e.getWeight()).append("]");
- }
- sb.append(";\n");
- }
+ sb.append(isDirected ? "digraph {\n" : "graph {\n");
+ sb.append(" rankdir=LR;\n");
- // Affichage des nœuds isolés (ceux qui n’ont aucune arête)
- Set nodesWithEdges = new HashSet<>();
- for (Edge e : edges) {
- nodesWithEdges.add(e.getNodeFrom());
- nodesWithEdges.add(e.getNodeTo());
- }
+ for (Map.Entry> entry : adjEdList.entrySet()) {
+ Node from = entry.getKey();
+ List edges = entry.getValue();
- for (Node node : adjEdList.keySet()) {
- if (!nodesWithEdges.contains(node)) {
- sb.append("\t").append(node.getId()).append(";\n");
+ // Case: isolated node (no outgoing edges)
+ if (edges.isEmpty()) {
+ sb.append(" ").append(from.getId()).append(";\n");
+ continue;
+ }
+
+ for (Edge e : edges) {
+ sb.append(" ")
+ .append(e.from().getId())
+ .append(arrow)
+ .append(e.to().getId());
+
+ // Add weight label if present
+ if (e.getWeight() != null) {
+ sb.append(" [label=\"").append(e.getWeight()).append("\"]");
+ }
+ sb.append(";\n");
}
}
- sb.append("}\n");
+ sb.append("}");
return sb.toString();
}
diff --git a/src/main/java/m1graphs2025/UndirectedGraph.java b/src/main/java/m1graphs2025/UndirectedGraph.java
index 45ac02e..9774326 100644
--- a/src/main/java/m1graphs2025/UndirectedGraph.java
+++ b/src/main/java/m1graphs2025/UndirectedGraph.java
@@ -204,10 +204,10 @@ public class UndirectedGraph extends Graph {
}
return closure;
}
-
- public static Graph fromDotFile(String filename) {
+ // ======================
+ public static UndirectedGraph fromDotFile(String filename) {
Map> adjEdList = new HashMap<>();
- Graph g = new UndirectedGraph(adjEdList);
+ UndirectedGraph g = new UndirectedGraph(adjEdList);
try (BufferedReader dot = new BufferedReader(new FileReader(filename))) {
String line;
--
GitLab