📄 eulercirclefinder.java
字号:
package salvo.jesus.graph.algorithm;import salvo.jesus.graph.*;import javax.swing.*;import java.util.*;import salvo.jesus.graph.visual.*;/** * This class finds an Euler circle in a graph. A Euler circle is a path through * a graph that visits every edge of the graph excatly once and ends at the same * vertex it started. * <p>This algortihm does <strong>not</strong> check if the searched graph is entirely * connected. It is the callers responsibility to assure the graph is entirely connected. * Otherwise an Euler circle in any connected set of the graph will be found. * <p>If there is no Euler circle in the graph a GraphException will be thrown when the * graph is searched. Euler's Circle Law says a graph has a Euler circle if and only if * the graph is entirely connected and every vertex has an even degree (i.e. number of * edges). * <p>It seems to me that the time needed to find a Euler circle using this * algorithm is proportional to the number of edges in the graph. * @author David Dannberg (9dannber@informatik.uni-hamburg.de) */public class EulerCircleFinder { private final static EulerCircleFinder s_Singleton = new EulerCircleFinder(); private static EulerCircleFinder getSingletonInstance() { return s_Singleton; } private Graph m_Graph; private EulerCircleFinder () {} /** * Sets the graph that is to be searched for a Euler circle. * * @param g the graph to be searched * @throws IllegalArgumentException if <code>g</code> has no vertices. */ private void setGraph (Graph g) { if (g.getVerticesCount() == 0) throw new IllegalArgumentException ("Graph has no vertices"); try { m_Graph = clone (g); } catch (Exception e) { e.printStackTrace(); throw new IllegalArgumentException ("Exception while creating copy of the Graph"); } } private Graph getGraph () { return m_Graph; } private static void addCircle (List targetCircle, List newCircle) { // First and last element of newCircle must be same if (newCircle.size() == 0 || newCircle.get(0) != newCircle.get(newCircle.size()-1)) throw new IllegalArgumentException(); int position = targetCircle.indexOf(newCircle.get(0)); targetCircle.remove(position); targetCircle.addAll(position, newCircle); } /** * Removes edges from the graph. Those vertices that have a degree of 0 (i.e. have no * more edges) after removing the given edges also removed. * * @param edgesToRemove a list of <code>edge</code> objects wich should be removed from * the used graph. */ private void removeEdges(List edgesToRemove) throws Exception { for (Iterator it = edgesToRemove.iterator();it.hasNext();) { getGraph().removeEdge((Edge)it.next()); } Set lostVertices = getGraph().getVertices(0); for (Iterator it = lostVertices.iterator();it.hasNext();) { getGraph().remove((Vertex)it.next()); } } /** * Returns an edge of a specified vertex, which is <strong>not</strong> contained in * a list. * @return The edge returned matches both of the following conditions: * <ul> * <li>The edge is an incident edge of the given vertex <code>v</code></li> * <li>There is no object contained in the given list <code>usedEdges</code> that * equals the edge</li> * </ul> * If the graph has no edge that matches these conditions <code>null</code> is * returned */ private Edge findUnusedEdge (Vertex v, List usedEdges) { List vertexEdges = getGraph().getEdges(v); vertexEdges.removeAll(usedEdges); if (vertexEdges.size() > 0) { return (Edge)vertexEdges.get(0); } else { return null; } } /** * Returns a Path wich is a Euler circle in the given graph or <code>null</code> * if there is no Euler circle in this graph. * @see #setGraph */ public static Path find (Graph g) { getSingletonInstance().setGraph(g); try { List eulerCirlce = getSingletonInstance().findEulerCircle((Vertex)getSingletonInstance().getGraph().getVerticesIterator().next()); Path eulerPath = new PathImpl (); for (Iterator it = eulerCirlce.iterator();it.hasNext();) { try { eulerPath.add((Vertex)it.next()); } catch (Exception e) { System.err.println("Could not create Path-Object. Path vertices are: " + eulerCirlce); System.err.println("Original Exception was"); e.printStackTrace(); } } return eulerPath; } catch (NoEulerCircleException nece) { return null; } } private List findEulerCircle(Vertex startVertex) throws NoEulerCircleException { switch (getGraph().getVerticesCount()) { case 0 : throw new RuntimeException ("Error in finding algorithm"); // should not occur case 1 : return Arrays.asList(new Vertex[] { startVertex }); default: Vertex currentVertex = startVertex; List visitedEdges = new LinkedList(); List visitedVertices = new LinkedList(); visitedVertices.add(startVertex); // Find a primary circle in the graph within this loop do { Edge unusedEdge = findUnusedEdge(currentVertex, visitedEdges); if (unusedEdge == null) { throw new NoEulerCircleException (); } currentVertex = unusedEdge.getOppositeVertex(currentVertex); visitedEdges.add(unusedEdge); visitedVertices.add(currentVertex); } while (startVertex != currentVertex); // remove primary circle from the graph try { removeEdges (visitedEdges); } catch (Exception e) { throw new RuntimeException ("Error in finding algorithm"); // should not occur } List primaryCircle = new LinkedList (visitedVertices); // find more circles in the remaining graph and combine all circles to one for (Iterator it = primaryCircle.iterator();it.hasNext();) { Vertex v = (Vertex)it.next(); if (getGraph().cloneVertices().contains(v)) { addCircle(visitedVertices, findEulerCircle(v)); } } return visitedVertices; } }/* // Just a test public static void main (String[] args) throws Exception { Graph g = new GraphImpl (); Vertex v1 = new VertexImpl ("1"); Vertex v2 = new VertexImpl ("2"); Vertex v3 = new VertexImpl ("3"); Vertex v4 = new VertexImpl ("4"); Vertex v5 = new VertexImpl ("5"); Vertex v6 = new VertexImpl ("6"); Vertex v7 = new VertexImpl ("7"); Vertex v8 = new VertexImpl ("8"); g.add(v1); g.add(v2); g.add(v3); g.add(v4); g.add(v5); g.add(v6); g.add(v7); g.add(v8); g.addEdge(v1,v2); g.addEdge(v2,v3); g.addEdge(v3,v4); g.addEdge(v4,v1); g.addEdge(v2,v4); g.addEdge(v4,v5); g.addEdge(v5,v2); g.addEdge(v5,v6); g.addEdge(v6,v8); g.addEdge(v8,v5); g.addEdge(v8,v7); g.addEdge(v7,v1); g.addEdge(v1,v8); System.out.println(find(g)); GraphEditor gp = new GraphEditor (g); JFrame frame = new JFrame (); frame.setContentPane(gp); frame.setSize(300,200); frame.setVisible(true); }*/ public static Graph clone(Graph g) throws Exception { Graph clone = new GraphImpl(); for (Iterator vertexIt = g.getVerticesIterator();vertexIt.hasNext();) { Vertex v = (Vertex)vertexIt.next(); clone.add(v); } for (Iterator vertexIt = clone.getVerticesIterator();vertexIt.hasNext();) { Vertex v = (Vertex)vertexIt.next(); List edges = g.getEdges(v); for (Iterator edgesIt = edges.iterator();edgesIt.hasNext();) { Edge e = (Edge)edgesIt.next(); if (e.getVertexA() == v) { clone.addEdge(e); } } } return clone; }}class NoEulerCircleException extends GraphException {}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -