diff --git a/Enoncés/TP/TP6_Graphe.pdf b/Enoncés/TP/TP6_Graphe.pdf
new file mode 100644
index 0000000..4c0d564
Binary files /dev/null and b/Enoncés/TP/TP6_Graphe.pdf differ
diff --git a/src/TP6/Graph.java b/src/TP6/Graph.java
new file mode 100644
index 0000000..e41a2b1
--- /dev/null
+++ b/src/TP6/Graph.java
@@ -0,0 +1,413 @@
+package TP6;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+
+/** This class implements a graph as an adjacency-list.
+ * The graph may be oriented or not and may store any information
+ * on nodes and on edges using (key,value) principle where key is a String
+ * and value an Object.
+ * Nodes N are retrieved using their hashcode.
+ *
Use {@code GraphTest} class for testing it.
+ *
Use {@code GraphIO} class for converting a graph into an array, an image, to be displayed in a Graphics...
+ *
Use {@code GraphAlgorithms} class for using algorithms on this graph structure like shortestPath.
+ *
+ * @author Dr. Denis Pallez
+ * http://denispallez.i3s.unice.fr
+ *
+ * @param N represents the types of Nodes.
+ */
+public class Graph {
+ // all information about a node is stored in nodeInfo inner class
+ // using (String, Object) principle.
+ // orientation of the graph
+ private boolean orientedGraph ;
+ // Integer represents the hashcode of node of the graph.
+ private LinkedHashMap> ladj ;
+
+ // make disable constructor by default
+ private Graph() {}
+
+ /**
+ * Build an oriented or unoriented graph
+ * @param oriented Orientation of all edges of the graph
+ */
+ public Graph(boolean oriented) {
+ ladj = new LinkedHashMap>() ;
+ orientedGraph = oriented ;
+ }
+
+ /** Build a graph from another graph {@code g}.
+ * Make a deep copy of any information contained
+ * in the graph.
+ *
+ * @param g the graph
+ */
+ public Graph(Graph g) {
+ orientedGraph=g.orientedGraph ;
+ for (Integer code1:g.ladj.keySet() ) {
+ N node1 = g.getNode(code1) ;
+ addNode(node1) ;
+ // add all values on node
+ for (String key:g.ladj.get(code1).getAttributesOnNode().keySet()) {
+ addAttributeOnNode(node1, key, g.getAttributeOnNode(node1, key)) ;
+ }
+ for (Integer code2:g.ladj.get(code1).edges.keySet()) {
+ // add all values contained on edge node1->node2
+ N node2 = g.getNode(code2) ;
+ for (String key:g.ladj.get(code1).getAttributesOnEdge(code2).keySet()) {
+ addAttributeOnEdge(node1, node2, key,g.ladj.get(code1).getAttributeOnEdge(code2, key)) ;
+ }
+ }
+ }
+ }
+
+ /** Are edges oriented or not ?
+ *
+ * @return a boolean representing whether all edges of the graph are oriented or not
+ */
+ public boolean isOriented() {
+ return orientedGraph;
+ }
+
+ /**
+ * Get a number that should be unique in the graph.
+ * Method is based on hashcode of {@code node}.
+ * @param node
+ * @return a unique number of the node in the graph
+ */
+ private Integer getCode(N node) {
+ return node.hashCode() ;
+ }
+
+
+ /**
+ * Retrieve node in the graph using its {@code code}.
+ * @param code Integer representing the hashcode of the object.
+ * @return an object of type N used when adding the node in the graph.
+ */
+ private N getNode(Integer code) {
+ if (ladj.containsKey(code)) {
+ return ladj.get(code).getNode() ;
+ }
+ else return null ;
+ }
+
+ /** Is node {@code node} stored in the graph?
+ */
+ public boolean isNode(N node) {
+ return ladj.containsKey(getCode(node)) ;
+ }
+
+ /** Add node {@code node} in the graph.
+ * Use the hashcode of node as a key.
+ * @param node node to add in the graph.
+ */
+ public void addNode(N node) {
+ if (!isNode(node)) {
+ ladj.put(getCode(node), new nodeInfo(node));
+ }
+ }
+
+ /** Add information on node {@code node}.
+ *
+ * @param node where information is stored
+ * @param key a String value for retrieving the information
+ * @param value information to store on the node associated to key
+ */
+ public void addAttributeOnNode(N node, String key, Object value) {
+ Integer code = getCode(node) ;
+ addNode(node) ;
+ ladj.get(code).addAttributeOnNode(key,value) ;
+ }
+
+ /** Retrieve information called {@code key} on node {@code node}.
+ * @param node the node where information is stored
+ * @param key the key information to retrieve
+ */
+ public Object getAttributeOnNode(N node, String key) {
+ return ladj.get(getCode(node)).getAttributeOnNode(key) ;
+ }
+
+ public HashMap getAttributesOnNode(N node) {
+ return ladj.get(getCode(node)).properties ;
+ }
+
+ /** Add an edge between nodes {@code node1} and {@code node2}
+ * with an information called {@code key}
+ * and represented by {@code value}.
+ * If {@code node1} or {@code node2} are not in the graph,
+ * nodes are automatically added.
+ * If graph is not oriented, add automatically an edge between {@code node2} and {@code node1}.
+ */
+ public void addAttributeOnEdge(N node1, N node2, String key, Object value) {
+ if (!isNode(node1)) {
+ addNode(node1) ;
+ }
+ if (!isNode(node2)) {
+ addNode(node2) ;
+ }
+ ladj.get(getCode(node1)).addAttributeOnEdge(getCode(node2),key,value) ;
+ if (!orientedGraph) {
+ ladj.get(getCode(node2)).addAttributeOnEdge(getCode(node1),key,value) ;
+ }
+ }
+
+ /** Retrieve information called {@code key} on edge
+ * between nodes {@code node1} and {@code node2}.
+ * If edge does not exist, return null.
+ * @param node1
+ * @param node2
+ * @param key
+ */
+ public Object getAttributeOnEdge(N node1, N node2, String key) {
+ if (isNode(node1) && isNode(node2)) {
+ return ladj.get(getCode(node1)).getAttributeOnEdge(getCode(node2),key) ;
+ }
+ else return null ;
+ }
+
+ public HashMap getAttributesOnEdge(N node1, N node2) {
+ if (isNode(node1) && isNode(node2)) {
+ return ladj.get(getCode(node1)).getAttributesOnEdge(getCode(node2)) ;
+ }
+ else return null ;
+ }
+
+ /** Remove edge between nodes {@code node1} and {@code node2}.
+ * If graph is not oriented edge between nodes {@code node2} and {@code node1}
+ * is also deleted.
+ * @param node1
+ * @param node2
+ */
+ public void deleteEdge(N node1, N node2) {
+ Integer code1 = getCode(node1) ;
+ Integer code2 = getCode(node2) ;
+ if (isNode(node1) && isNode(node2)) {
+ // remove edge node1->node2
+ ladj.get(code1).clearAttributesOnEdge(code2);
+ ladj.get(code1).edges.remove(code2) ;
+ if (!orientedGraph) {
+ // remove edge node2->node1
+ ladj.get(code2).clearAttributesOnEdge(code1); ladj.get(code1).edges.remove(code1) ;
+ }
+ }
+ }
+
+ /** Remove node {@code node} and all incident edges.
+ * @param node
+ */
+ public void deleteNode(N node) {
+ Integer code = getCode(node) ;
+ if (ladj.containsKey(code)) {
+ // delete node in succ list of any node of the graph
+ for (Integer anynode:ladj.keySet()) {
+ ladj.get(anynode).removeEdge(code) ;
+ }
+ // delete the node
+ ladj.remove(code) ;
+ }
+ }
+
+ /** Remove information called {@code key} on all nodes and all edges of the graph.
+ */
+ public void deleteAttributes(String key) {
+ for (Integer code1:ladj.keySet()) {
+ ladj.get(code1).removeAttributeOnNode(key) ;
+ for (Integer code2:ladj.get(code1).getEdges().keySet()) {
+ ladj.get(code1).removeAttributeOnEdge(code2,key) ;
+ }
+ }
+ }
+
+ /** Is there an edge between nodes {@code node1} and {@code node2}
+ * considering any information stored in the graph ?
+ */
+ public boolean hasEdge(N node1, N node2) {
+ Integer code1 = getCode(node1) ;
+ Integer code2 = getCode(node2) ;
+ if (ladj.containsKey(code1) && ladj.containsKey(code2)) {
+ return ladj.get(code1).getAttributesOnEdge(code2)!=null ;
+ }
+ else return false ;
+ }
+
+ /** Is there an edge between nodes {@code node1} and {@code node2}
+ * considering {@code key} values ?
+ */
+ public boolean hasEdge(N node1, N node2, String key) {
+ Integer code1 = getCode(node1) ;
+ Integer code2 = getCode(node2) ;
+ if (ladj.containsKey(code1) && ladj.containsKey(code2)) {
+ return ladj.get(code1).getAttributeOnEdge(code2, key)!=null ;
+ }
+ else return false ;
+ }
+
+ /** return all descendants of node {@code node}.
+ */
+ public LinkedList getAdjacentNodes(N node) {
+ LinkedList list= new LinkedList() ;
+ for (Integer codedesc:ladj.get(getCode(node)).getEdges().keySet()) {
+ list.add(getNode(codedesc)) ;
+ }
+ return list ;
+ }
+
+ /** return all descendants of node {@code node} according key .
+ */
+ public LinkedList getAdjacentNodes(N node, String key) {
+ LinkedList list= new LinkedList() ;
+ for (Integer codedesc:ladj.get(getCode(node)).getEdges().keySet()) {
+ if (getAttributeOnEdge(node, getNode(codedesc), key) != null)
+ list.add(getNode(codedesc)) ;
+ }
+ return list ;
+ }
+
+
+ /** return nodes that has a edge towards node {@code node}
+ */
+ public LinkedList getIncidenceNodes(N node) {
+ LinkedList list = new LinkedList() ;
+ for (Integer code2:ladj.keySet()) {
+ if (ladj.get(code2).getEdges().containsKey(getCode(node))) {
+ list.add(getNode(code2)) ;
+ }
+ }
+ return list ;
+ }
+
+ /** return nodes that has a edge towards node {@code node}
+ * according to key {@code key}
+ */
+ public LinkedList getIncidenceNodes(N node, String key) {
+ LinkedList list = new LinkedList() ;
+ for (Integer code2:ladj.keySet()) {
+ if (ladj.get(code2).getAttributeOnEdge(getCode(node), key)!=null) {
+ list.add(getNode(code2)) ;
+ }
+ }
+ return list ;
+ }
+
+ /** Return all nodes stored in the graph.
+ */
+ public LinkedList getNodes() {
+ LinkedList list= new LinkedList() ;
+ for (Integer code:ladj.keySet()) {
+ list.add(getNode(code)) ;
+ }
+ return list ;
+ }
+
+ @Override
+ public String toString() {
+ String graphText ="" ;
+ for (Integer code1:ladj.keySet()) {
+ graphText+=getNode(code1)+"{";
+ for (String keynode:ladj.get(code1).getAttributesOnNode().keySet()) {
+ graphText+= "(" + keynode +"," + ladj.get(code1).getAttributeOnNode(keynode)+")," ;
+ }
+ graphText+="} :\t{" ;
+ for (Integer code2:ladj.get(code1).edges.keySet()) {
+ graphText+="->"+getNode(code2)+ladj.get(code1).getAttributesOnEdge(code2)+"," ;
+ }
+ graphText+="}\n" ;
+ }
+ return graphText ;
+ }
+
+ // create a wrapper class for a node that will contain
+ // marks for that node and edges.
+ // A node can contain several informations represented
+ // by a HashMap
+ // An edge can contain several informations represented
+ // by a HashMap
+ private class nodeInfo {
+ private N node ;
+ private HashMap properties ;
+ private LinkedHashMap> edges ;
+
+ private nodeInfo() {}
+ public nodeInfo(N value) {
+ properties = new HashMap() ;
+ //properties.put(privateKey, value) ;
+ node = value ;
+ edges = new LinkedHashMap>() ;
+ }
+
+ public N getNode() {
+ return node ;
+ //return (N)properties.get(privateKey) ;
+ }
+
+ public Object getAttributeOnNode(String key) {
+ return properties.get(key) ;
+ }
+
+ public HashMap getAttributesOnNode() {
+ return properties;
+ }
+
+ public HashMap> getEdges() {
+ return edges ;
+ }
+
+ public void addAttributeOnNode(String key, Object value) {
+ properties.put(key, value) ;
+ }
+
+ public void removeAttributeOnNode(String key) {
+ properties.remove(key) ;
+ }
+
+ public Object getAttributeOnEdge(Integer code2, String key) {
+ if (edges.containsKey(code2))
+ return edges.get(code2).get(key) ;
+ else return null ;
+ }
+
+ public HashMap getAttributesOnEdge(Integer code2) {
+ if (edges.containsKey(code2))
+ return edges.get(code2) ;
+ else return null ;
+ }
+
+ public void addAttributeOnEdge(Integer code2, String key, Object value) {
+ if (!edges.containsKey(code2)) {
+ edges.put(code2, new HashMap()) ;
+ }
+ edges.get(code2).put(key, value) ;
+ }
+
+ public void removeAttributeOnEdge(Integer code2, String key) {
+ if (edges.containsKey(code2)) {
+ edges.get(code2).remove(key) ;
+ }
+ }
+
+ public void removeEdge(Integer code2) {
+ if (edges.containsKey(code2)) {
+ edges.get(code2).clear() ;
+ edges.remove(code2) ;
+ }
+ }
+
+ public void clearAttributesOnNode() {
+ properties.clear();
+ }
+
+ public void clearAttributesOnEdge(Integer node2) {
+ if (edges.containsKey(node2))
+ edges.get(node2).clear();
+ }
+ public void clearAllAttributes() {
+ clearAttributesOnNode();
+ for (Integer node2:edges.keySet()) {
+ clearAttributesOnEdge(node2) ;
+ }
+ }
+ }
+}