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) ; + } + } + } +}