JavaDoc


001    /**
002     * Copyright (c) 2003 Daffodil Software Ltd all rights reserved,
003     * Modifications Copyright (c) 2008 Regiscope Digital Imaging Co, LLC, All rights reserved.
004     * This program is free software; you can redistribute it and/or modify
005     * it under the terms of version 2 of the GNU General Public License as
006     * published by the Free Software Foundation.
007     * There are special exceptions to the terms and conditions of the GPL
008     * as it is applied to this software. See the GNU General Public License for more details.
009     *
010     * This program is distributed in the hope that it will be useful,
011     * but WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013     * GNU General Public License for more details.
014     *
015     * You should have received a copy of the GNU General Public License
016     * along with this program; if not, write to the Free Software
017     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018     */
019    
020    
021    package org.dbreplicator.graph;
022    
023    import org.apache.log4j.Logger;
024    import java.math.*;
025    import java.util.*;
026    import org.dbreplicator.replication.RepException;
027    
028    
029    
030    public class DirectedGraph
031        implements DGraph {
032    
033      protected static Logger log = Logger.getLogger(DirectedGraph.class.getName());
034    
035     //  The total amount of vertices in the graph.
036      private int totalVerticesGraph;
037    
038      /**
039       The total amount of edges in the graph. Needs to
040       be <CODE>long</CODE>, because more than
041       <CODE>Integer.MAX_VALUE</CODE> edges are allowed.
042       (Special measures are taken in this case, though.)
043       */
044      private long EdgesInGraph;
045    
046      // The current cylcle status when searching the entire graph.
047      private boolean cycleStatus;
048    
049    
050      // A linked list of all vertex objects in the graph,
051      // for iterative access. (Link to beginning of list)
052    
053      private ListElement mainVertexList;
054    
055     // A linked list of all edge objects in the graph,
056     // for iterative access. (Link to beginning of list)
057    
058      private ListElement mainEdgeList;
059    
060    
061       //The main hash table, which is an array of list elements,
062       //with a length that is always prime.
063      private ListElement[] mainHashTable;
064    
065    
066      ArrayList tablesInCycle=new ArrayList();
067    
068    
069      /**
070       A directed graph with weighted edges. Constructed with an
071       integer, which is the first size of the hash table.
072       */
073    
074      public DirectedGraph(int hashTableInit) {
075    
076        totalVerticesGraph = 0;
077        EdgesInGraph = 0;
078        mainVertexList = null;
079        mainEdgeList = null;
080        if (hashTableInit < 11) hashTableInit = 11;
081        mainHashTable = new ListElement[hashTableInit];
082        for (int i = 0; i < mainHashTable.length; i++) {
083          mainHashTable[i] = new ListElement();
084        }
085      }
086    
087    
088      /**
089        Does the hashing. Finds the
090        place where the object goes or is.
091        It wants an embedded vertex object
092        as its parameter, and it will return the
093        list element<UL>
094        <LI>where the object is or</LI>
095        <LI>the element BEFORE the element where
096        the object should go.</LI></UL>
097        In other words, it returns the list element
098        where the search terminates in the hash table.
099        @return ListElement instance where the object
100            is, or after which the object should come, the
101        testing of which case is the reality should be
102        done at the caller
103        @param objInVertex the object inside the vertex
104        that we want to find
105       */
106    
107            public ListElement searchVertex(Object objInVertex) {
108              ListElement endOfSearchChain;
109              Vertex vertex = null;
110              int index = Math.abs(objInVertex.hashCode()) %mainHashTable.length;
111              endOfSearchChain = mainHashTable[index];
112              if (endOfSearchChain.next == null) {
113                return endOfSearchChain;
114              }
115              while (endOfSearchChain.next != null) {
116                endOfSearchChain = endOfSearchChain.next;
117                vertex = (Vertex) endOfSearchChain.hangingVertexOrEdge;
118                if (vertex.vertexObject.equals(objInVertex)) {
119                  return endOfSearchChain;
120                }
121              }
122        return endOfSearchChain;
123      }
124    
125      /**
126        This method is used when we know that the vertex
127        is NOT in the hash table, and we want to keep all
128        edge associations. (during a full reHash() operation)
129        @param the JbVertex we wish to reinsert into table.
130        @return <tt>true</tt> if the hashing proceeds as normal.
131       */
132    
133      private boolean hashVertex(Vertex vertexToHash) {
134    
135        ListElement hanger = new ListElement(vertexToHash);
136        ListElement previous = searchVertex(vertexToHash.vertexObject);
137        previous.next = hanger;
138        return true;
139      }
140    
141      /**
142        Finds the edge-object between 2 vertices.
143        @param first The origin of the edge
144        @param second The destination of the edge
145        @throws java.lang.IllegalArgumentException if either of the
146        param vertices are not found in this graph
147        @return the edge from first to second, null if no edge from
148        first to second
149       */
150    
151      private Edge searchEdge(Object first, Object second)  {
152        //finding vertex1
153        ListElement targetLE = searchVertex(first);
154        Vertex firstVertex = (Vertex) targetLE.hangingVertexOrEdge;
155        if (firstVertex == null) {
156          return null;
157    //      throw new IllegalArgumentException("First param-vertex not found.");
158        }
159        if (!firstVertex.vertexObject.equals(first)){
160          return null;
161    //      throw new IllegalArgumentException("First param-vertex not found.");
162        }
163        //finding vertex2
164        targetLE = searchVertex(second);
165        Vertex secondVertex = (Vertex) targetLE.hangingVertexOrEdge;
166        if (secondVertex == null ){
167           return null;
168    //      throw new IllegalArgumentException("Second param-vertex not found.");
169        }
170        if (!secondVertex.vertexObject.equals(second)){
171           return null;
172    //      throw new IllegalArgumentException("Second param-vertex not found.");
173        }
174        //searching edge chain for Edge:(1 --> 2)
175        Edge edge;
176        for (ListElement i = firstVertex.firstEdge; i != null; i = i.next) {
177          edge = (Edge) i.hangingVertexOrEdge;
178          if (edge.targetVertex == secondVertex)
179            return edge;
180        }
181        return null;
182      }
183    
184      /**
185       Called when the addVertex-method sees that the load
186       of the hash table is > 1. Allocates a new hash table
187       with a length of at least 2x+1, where x is the old
188       length. The new length is (also) prime. Then iterates
189       through all vertex objects in graph and relocates them
190       into the new table accordingly.
191       @return <tt>true</tt> if all vertices successfully rehashed
192       into a new hash table
193       */
194    
195      private boolean reHash() {
196    
197        BigInteger ourPrime =
198            new BigInteger(String.valueOf(mainHashTable.length * 2 + 1));
199        BigInteger two = new BigInteger("2");
200        //probability that we end up with a non-prime
201        //is 1/32 (2^n where n=5, prob=rather small)
202        while (!ourPrime.isProbablePrime(5)) {
203          ourPrime = ourPrime.add(two);
204        }
205        //test if the new number is bigger than Integer.MAX_VALUE
206        //use "longValue" because "intValue" would not work, obviously
207        if (ourPrime.longValue() > Integer.MAX_VALUE) {
208          //then make the table size Integer.MAX_VALUE
209          mainHashTable = new ListElement[Integer.MAX_VALUE];
210        }
211        else {
212          //make the table size
213          mainHashTable = new ListElement[ourPrime.intValue()];
214        }
215        for (int k = 0; k < mainHashTable.length; k++) {
216          mainHashTable[k] = new ListElement();
217        }
218        //go throught the full vertex list and
219        //hash each into the new table
220        for (ListElement j = mainVertexList; j != null; j = j.next) {
221          if (!hashVertex( (Vertex) j.hangingVertexOrEdge))
222            return false;
223        }
224        return true;
225      }
226    
227      /**
228        Recursively seeks a cycle starting from the
229        vertex given as a parameter. Marks its way
230        through the vertices by setting the marker-
231        attribute in each vertex-object.
232        @param startVertex  Vertex where the search begins.
233       */
234    
235      public void findCycle(Vertex startVertex) {
236         if (cycleStatus == true)return;
237         if (startVertex.graphMarker > 0) {
238           cycleStatus = true;
239           return;
240         }
241         startVertex.graphMarker++;
242         Edge current;
243         for (ListElement i = startVertex.firstEdge; i != null; i = i.next) {
244           current = (Edge) i.hangingVertexOrEdge;
245           tablesInCycle.add(current.targetVertex);
246           findCycle(current.targetVertex);
247           current.targetVertex.graphMarker--;
248         }
249      }
250    
251      /**
252            Clears all vertex markers
253       */
254    
255      private void clearAllMarkers() {
256        Vertex vertex;
257        for (ListElement i = mainVertexList; i != null; i = i.next) {
258          vertex = (Vertex) i.hangingVertexOrEdge;
259          vertex.graphMarker = 0;
260        }
261      }
262    
263      /**
264        This method draws a "picture" of the main hash table.
265        It works nicely if the max chain length is ~< 4.
266        Of course it sorta scrolls the screen for big
267        graphs, so.. directing to a file isn't a bad
268        option sometimes. It does NOT attempt to draw any
269        kind of representation of the graph or edges or
270        anything complex like that. It can help in debugging
271        matters pertaining to the hash table structure.
272       */
273    
274      public String toString() {
275        String result = "";
276        Double load = new Double( (double) totalVerticesGraph /
277                                 (double) mainHashTable.length);
278        Vertex vertex;
279        for (int i = 0; i < mainHashTable.length; i++) {
280          for (ListElement j = mainHashTable[i]; j != null; j = j.next) {
281            vertex = (Vertex) j.hangingVertexOrEdge;
282            if (vertex == null) {
283              result += " nil";
284            }
285            else {
286              if (vertex.vertexObject != null)
287                result += "LEobj"; // vertex.vertexObject);
288            }
289            if (j.next != null) result += "-> ";
290            if (j.next == null) result += "-|\n";
291          }
292        }
293        result += "Vertex Total:    " + this.totalVerticesGraph + "\n";
294        result += "Hash Table size: " + this.mainHashTable.length + "\n";
295        result += "Load factor :    " + load + "\n";
296        return result;
297      }
298    
299    //---------------------------------------------------------------------
300    //  Predefined methods required in implementation. (interface)
301    //---------------------------------------------------------------------
302      /**
303         Compares the specified object with this directed graph for equality.
304         Returns <tt>true</tt> if the specified object is also a directed graph
305         and the two directed graphs have the same vertices and edges.
306         @param obj the object to be compared for equality with this directed
307         graph.
308         @return <tt>true</tt> if the specified Object is equal to this directed
309         graph.
310       */
311    
312      public boolean equals(Object obj) {
313        DGraph other;
314        try {
315          other = (DGraph) obj;
316        }
317        catch (java.lang.ClassCastException e) {
318          return false;
319        }
320    
321        if ( (other.vertexCount() != this.totalVerticesGraph) ||
322            (other.edgeCount() != this.EdgesInGraph)) {
323          return false;
324        }
325        //since equal number of vertices is now tested, we
326        //can jump out if total==0 (both==0)
327        if (totalVerticesGraph == 0)return true;
328        Vertex vertex;
329        Edge edge;
330        ListElement edgeLE;
331        for (ListElement i = mainVertexList; i != null; i = i.next) {
332          vertex = (Vertex) i.hangingVertexOrEdge;
333          Object thisObj = vertex.vertexObject; //shorthand assignment
334          if (!other.hasVertex(thisObj))return false;
335          //testing each edge from this vertex
336          edgeLE = vertex.firstEdge; //"edge-list-element"
337          for (edgeLE = vertex.firstEdge; edgeLE != null; edgeLE = edgeLE.next) {
338            edge = (Edge) edgeLE.hangingVertexOrEdge;
339            if (!other.hasEdge(thisObj, edge.targetVertex.vertexObject))return false;
340            if (other.edgeWeight(thisObj, edge.targetVertex.vertexObject) !=
341                edge.whatIsWeight()) {
342              return false;
343            }
344          }
345        }
346        //All vertices and edges tested to be equal.
347        //And we're still here. So it must be equal.
348    
349        return true;
350      }
351    
352      /**
353         Returns the hash code value for this directed graph.  The hash code of a
354         directed graph is defined to be the sum of the hash codes of the vertices
355         in the directed graph. The sum is allowed to overflow if needed. This
356         definition ensures that if <code>s1.equals(s2)</code> then
357         <code>s1.hashCode() == s2.hashCode()</code> for any two directed graphs
358         <code>s1</code> and <code>s2</code>, as required by the general contract
359         of the <tt>java.lang.Object.hashCode</tt> method.
360         @return the hash code value for this directed graph.
361       */
362    
363      public int hashCode() {
364        int code = 0;
365        Vertex vertex;
366        for (ListElement i = mainVertexList; i != null; i = i.next) {
367          vertex = (Vertex) i.hangingVertexOrEdge;
368          code += vertex.vertexObject.hashCode();
369        }
370        return code;
371      }
372    
373      /**
374         Adds the specified vertex to this directed graph if the vertex is not
375         null and the vertex is not already present in this directed graph. More
376         formally, adds the specified vertex <code>obj</code> to this directed
377         graph if <code>obj != null</code> and this directed graph contains no
378         vertex <code>e</code> such that <code>obj.equals(e)</code>. The number of
379         vertices in this directed graph may not exceed <tt>Integer.MAX_VALUE</tt>.
380         @param obj the vertex to be added to this directed graph.
381         @return <tt>true</tt> if the specified vertex was added to this directed
382         graph.
383         @throws java.lang.IllegalStateException if this directed graph contains
384         the maximum number of vertices.
385         @throws java.lang.IllegalArgumentException if a specified vertex is null.
386       */
387    
388      public boolean addVertex(Object obj) throws RepException {
389        if (obj == null){
390           throw new RepException("REP020",new Object[]{"","Param-vertex was null."});
391        }
392        if (obj == this){
393          throw new RepException("REP020",new Object[]{"","Param-vertex cannot be this graph."});
394        }
395        if (totalVerticesGraph + 1 > Integer.MAX_VALUE){
396           throw new RepException("REP020",new Object[]{"","Vertex count exceeds Integer.MAX_VALUE!"});
397        }
398        if (totalVerticesGraph + 1 > mainHashTable.length) reHash();
399        Vertex theNewVertex = new Vertex(obj);
400        ListElement place = searchVertex(obj);
401        if (place.hangingVertexOrEdge != null) {
402          Vertex lastFound = (Vertex) place.hangingVertexOrEdge;
403          if (lastFound.vertexObject.equals(obj)) {
404            return false; //already exists in table!!
405          }
406        }
407        ListElement newHashLE = new ListElement(theNewVertex);
408        place.next = newHashLE;
409        ListElement newListLE = new ListElement(theNewVertex);
410        newListLE.next = mainVertexList;
411        mainVertexList = newListLE;
412        totalVerticesGraph++;
413        return true;
414      }
415    
416      /**
417         Returns <tt>true</tt> if this directed graph contains the specified
418         vertex.  More formally, returns <tt>true</tt> if and only if
419         <code>obj != null</code> and this directed graph contains a vertex
420         <code>e</code> such that <code>obj.equals(e)</code>.
421         @param obj the vertex whose presence in this directed graph is to be
422         tested.
423         @return <tt>true</tt> if this directed graph contains the specified
424         vertex.
425         @throws java.lang.IllegalArgumentException if the specified vertex is
426         null.
427       */
428    
429      public boolean hasVertex(Object obj) {
430        if (obj == null) {
431          return false;
432    //      throw new IllegalArgumentException("Param-vertex is null.");
433        }
434        Vertex vertex;
435        ListElement requested = searchVertex(obj);
436        vertex = (Vertex) requested.hangingVertexOrEdge;
437        if (vertex == null)
438          return false; //no chain even exists at table[hash(obj)]
439        if (vertex.vertexObject.equals(obj)) {
440          return true;
441        }
442        return false; //object was not in collision chain
443      }
444    
445      /**
446         Returns <tt>true</tt> if there are vertices in this directed graph.
447         @return <tt>true</tt> if there are vertices in this directed graph.
448       */
449    
450      public boolean hasVertices() {
451        return (totalVerticesGraph > 0);
452      }
453    
454      /**
455         Returns the number of vertices in this directed graph.
456         @return the number of vertices in this directed graph.
457       */
458    
459      public int vertexCount() {
460        return (int) totalVerticesGraph;
461      }
462    
463      /**
464         Returns an array containing all vertices in this directed graph. The
465         vertices need not be in any special order.
466         <p>
467         The returned array will be "safe" in that no references to it are
468         maintained by this directed graph. In other words, this method must
469         allocate a new array even if this collection is backed by an array. The
470         caller is thus free to modify the returned array.
471         @return an array containing all vertices in this directed graph.
472       */
473    
474      public Object[] verticesToArray() {
475        Object[] arrayOfAllVertices = new Object[totalVerticesGraph];
476        int j = 0; // alternate counter for array
477        Vertex vertex;
478        for (ListElement i = mainVertexList; i != null; i = i.next) {
479          vertex = (Vertex) i.hangingVertexOrEdge;
480          arrayOfAllVertices[j++] = vertex.vertexObject;
481        }
482        return arrayOfAllVertices;
483      }
484    
485      /**
486         Adds an edge of a specified weight from the vertex <tt>first</tt> to the
487         vertex <tt>second</tt>.
488         @param first the vertex that the edge leaves from.
489         @param second the vertex that the edge enters.
490         @param weight the non-negative weight of the edge.
491         @return <tt>true</tt> if the specified vertex was added to this directed
492         graph, <tt>false</tt> if there already is an edge from the vertex
493         <tt>first</tt> to the vertex <tt>second</tt>.
494         @throws java.lang.IllegalArgumentException if a specified vertex was null
495         or not found in this directed graph, or if the specified weight was
496         negative.
497       */
498    
499      public boolean addEdge(java.lang.Object first, java.lang.Object second,
500                             int weight) throws RepException {
501        if (weight < 0){
502          throw new RepException("REP020",new Object[]{"","Weight was negative."});
503        }
504        if (hasEdge(first, second))return false;
505        //finding target vertex
506        ListElement requestedLE = searchVertex(second);
507        Vertex targetVertex = (Vertex) requestedLE.hangingVertexOrEdge;
508        if (targetVertex == null){
509          throw new RepException("REP020",new Object[]{"","Second param-vertex (target) not found."});
510        }
511        //finding source vertex
512        requestedLE = searchVertex(first);
513        Vertex sourceVertex = (Vertex) requestedLE.hangingVertexOrEdge;
514        if (sourceVertex == null){
515          throw new RepException("REP020",new Object[]{"","First param-vertex (source) not found."});
516        }
517        //creating new edge, then creating 2 LEobjects with it.
518        Edge theNewEdge = new Edge(targetVertex, weight);
519        ListElement hangerInVertex = new ListElement(theNewEdge);
520        ListElement hangerInList = new ListElement(theNewEdge);
521        //adding hangerInVertex to beginning of edge chain inside vertex
522        hangerInVertex.next = sourceVertex.firstEdge;
523        sourceVertex.firstEdge = hangerInVertex;
524        //incrementing  out degree of child
525        sourceVertex.addOutDegree();
526        //incrementing  in degree of parent
527        targetVertex.addInDegree();
528        //adding listLEobject to beginning of
529        //main linked edge list
530        hangerInList.next = mainEdgeList;
531        mainEdgeList = hangerInList;
532        EdgesInGraph++;
533        return true;
534      }
535    
536      /**
537         Returns <tt>true</tt> if this directed graph contains an edge that leaves
538         from the vertex <tt>first</tt> and enters the vertex <tt>second</tt>.
539         @param first the vertex that the edge should leave from.
540         @param second the vertex that the edge should enter.
541         @return <tt>true</tt> if this directed graph contains an edge that leaves
542         from the vertex <tt>first</tt> and enters the vertex <tt>second</tt>.
543         @throws java.lang.IllegalArgumentException if a specified vertex was null
544         or not found in this directed graph.
545       */
546    
547      public boolean hasEdge(java.lang.Object first, java.lang.Object second) {
548        if (searchEdge(first, second) != null)return true;
549        //no exceptions actually need to be thrown here, as
550        //the real work is doen by the helper method findEdge()
551        return false;
552      }
553    
554      /**
555         Returns the weight of the edge that leaves from the vertex <tt>first</tt>
556         and enters the vertex <tt>second</tt>.
557         @param first the vertex that the edge should leave from.
558         @param second the vertex that the edge should enter.
559         @return the weight of the edge that leaves from the vertex <tt>first</tt>
560         and enters the vertex <tt>second</tt>. Returns -1 if there is no such
561         edge.
562         @throws java.lang.IllegalArgumentException if a specified vertex was null
563         or not found in this directed graph.
564       */
565    
566      public int edgeWeight(java.lang.Object first, java.lang.Object second){
567        Edge targetEdge = searchEdge(first, second);
568        if (targetEdge == null)return -1;
569        return targetEdge.whatIsWeight();
570      }
571    
572      /**
573         Returns the number of edges that enter the specified vertex.
574         @param obj    Object of the vertex that the edges should enter.
575         @return the number of edges that enter the specified vertex.
576         @throws java.lang.IllegalArgumentException if a specified vertex was null
577         or not found in this directed graph.
578       */
579    
580      public int inDegree(java.lang.Object obj) throws RepException {
581        //check if the obj is null
582        if (obj == null){
583           throw new RepException("REP020",new Object[]{"","Param vertex object was null."});
584        }
585        ListElement requested;
586        requested = searchVertex(obj);
587        Vertex vertex = (Vertex) requested.hangingVertexOrEdge;
588        if (vertex == null) {
589           throw new RepException("REP020",new Object[]{"","Param vertex not found in graph. (hash index empty)"});
590        }
591        if (vertex.vertexObject.equals(obj)) {
592          return vertex.whatIsInDegree();
593        }
594        else {
595          //was not found in hash table
596            throw new RepException("REP020",new Object[]{"","Param vertex not found in graph. (not in collision chain)"});
597        }
598      }
599    
600      /**
601         Returns the number of edges that leave from the specified vertex.
602         @param obj the vertex that the edges should leave from.
603         @return the number of edges that leave from the specified vertex.
604         @throws java.lang.IllegalArgumentException if a specified vertex was null
605         or not found in this directed graph.
606       */
607    
608      public int outDegree(java.lang.Object obj) throws RepException {
609        //check if the obj is null
610        if (obj == null){
611            throw new RepException("REP020",new Object[]{"","Param vertex object was null."});
612        }
613        ListElement requested;
614        requested = searchVertex(obj);
615        Vertex vertex = (Vertex) requested.hangingVertexOrEdge;
616        if (vertex == null) {
617          throw new RepException("REP020",new Object[]{"","Param vertex not found in graph. (hash index empty)"});
618        }
619        if (vertex.vertexObject.equals(obj)) {
620          return vertex.whatIsOutDegree();
621        }
622        else {
623          //was not found in hash table
624          throw new RepException("REP020",new Object[]{"","Param vertex not found in graph. (not in collision chain)"});
625        }
626      }
627    
628      /**
629         Returns an array containing all vertices that are adjacent to the
630         specified vertex. A vertex v is adjacent to a vertex u if there is an
631         edge that leaves from u and enters v.
632         <p>
633         The returned array will be "safe" in that no references to it are
634         maintained by this directed graph. In other words, this method must
635         allocate a new array even if this collection is backed by an array. The
636         caller is thus free to modify the returned array.
637         @param obj the specified vertex.
638         @return an array containing all vertices that are adjacent to the
639         specified vertex.
640         @throws java.lang.IllegalArgumentException if a specified vertex was null
641         or not found in this directed graph.
642       */
643    
644      public Object[] adjacentsOf(java.lang.Object obj) throws  RepException {
645        if (obj == null){
646          throw new RepException("REP020",new Object[]{"","Null parameter specified."});
647        }
648        //finding source vertex
649        ListElement requested = searchVertex(obj);
650        Vertex vertex = (Vertex) requested.hangingVertexOrEdge;
651        if (vertex == null) {
652          throw new RepException("REP020",new Object[]{"","Param vertex not found in graph. (hash index empty)"});
653        }
654        if (vertex.vertexObject.equals(obj)) {
655          Object[] arrayOfAdjacents = new Object[vertex.whatIsOutDegree()];
656          ListElement theEdgeHanger = vertex.firstEdge;
657          Edge theEdge;
658          for (int i = 0; i < arrayOfAdjacents.length; i++) {
659            theEdge = (Edge) theEdgeHanger.hangingVertexOrEdge;
660            arrayOfAdjacents[i] = theEdge.targetVertex.vertexObject;
661            theEdgeHanger = theEdgeHanger.next;
662          }
663          return arrayOfAdjacents;
664        }
665        else {
666          //was not found in hash table
667          throw new RepException("REP020",new Object[]{"","Param vertex not found in graph. (not in collision chain)"});
668        }
669      }
670    
671      /**
672         <p>Returns <tt>true</tt> if the specified vertex is isolated. A vertex is
673         isolated if there are no edges leaving from or entering the vertex, or
674         the only edge leaving from the vertex enters the vertex itself and the
675         only edge entering the vertex leaves from the vertex itself.
676         @param obj the vertex that is to be tested for isolation.
677         @return <tt>true</tt> if the specified vertex is isolated.
678         @throws java.lang.IllegalArgumentException if a specified vertex was null
679         or not found in this directed graph.
680       */
681    
682      public boolean isIsolated(java.lang.Object obj) throws RepException {
683        if (obj == null){
684           throw new RepException("REP020",new Object[]{"","The parameter given was null."});
685        }
686        ListElement targetLE = searchVertex(obj);
687        Vertex thisVertex = (Vertex) targetLE.hangingVertexOrEdge;
688        if (thisVertex == null){
689           throw new RepException("REP020",new Object[]{"","Specified vertex not found in graph. (hash index empty)"});
690        }
691        if (thisVertex.vertexObject != obj){
692           throw new RepException("REP020",new Object[]{"","Specified vertex not found in graph. (not in collision chain)"});
693        }
694        if ( (thisVertex.whatIsInDegree() == 0) &&
695            (thisVertex.whatIsOutDegree() == 0))return true;
696    // if it is a self loop i.e  A<-->A
697        if ( (thisVertex.whatIsInDegree() == 1) &&
698            (thisVertex.whatIsOutDegree() == 1)) {
699          targetLE = thisVertex.firstEdge;
700          Edge onlyEdge = (Edge) targetLE.hangingVertexOrEdge;
701          if (onlyEdge.targetVertex == thisVertex)return true;
702        }
703        return false;
704      }
705    
706      /**
707         Returns <tt>true</tt> if there are edges in this directed graph.
708         @return <tt>true</tt> if there are edges in this directed graph.
709       */
710    
711      public boolean hasEdges() {
712        return (EdgesInGraph > 0);
713      }
714    
715      /**
716         Returns the number of edges in this directed graph. If this directed
717         graph contains more than <tt>Integer.MAX_VALUE</tt> edges, returns
718         <tt>Integer.MAX_VALUE</tt>.
719         @return the number of edges in this directed graph.
720       */
721    
722      public int edgeCount() {
723        if (EdgesInGraph > Integer.MAX_VALUE) {
724          return Integer.MAX_VALUE;
725        }
726        else {
727          return (int) EdgesInGraph;
728        }
729      }
730    
731      /**
732         Returns the sum of the weights of all edges in this directed graph. If
733         the sum is more than <tt>Integer.MAX_VALUE</tt>, returns
734         <tt>Integer.MAX_VALUE</tt>.
735         @return the sum of the weights of all edges in this directed graph.
736       */
737    
738      public int edgeWeight() {
739        //check for edges then
740        //create some vars for intermediate storage
741        if (this.EdgesInGraph == 0)return 0;
742        long sum = 0;
743        Edge edge;
744        //go through the mainEdgeList
745        //increment sum
746        for (ListElement i = mainEdgeList; i != null; i = i.next) {
747          edge = (Edge) i.hangingVertexOrEdge;
748          if (sum + edge.whatIsWeight() > Integer.MAX_VALUE) {
749            return Integer.MAX_VALUE;
750          }
751          sum += edge.whatIsWeight();
752        }
753        return (int) sum;
754      }
755    
756      /**
757         Returns an array of all of the vertices in this directed graph in some
758         topological sort order. <p>
759         The returned array will be "safe" in that no references to it are
760         maintained by this directed graph. In other words, this method must
761         allocate a new array even if this collection is backed by an array. The
762         caller is thus free to modify the returned array.
763         @return an array of all of the vertices in this directed graph in some
764         topological sort order. Returns null if no topological sort is possible.
765       */
766    
767      public Object[] topologicalSort() {
768        if (hasCycle() == true) {
769          //cycle found, no topological sort possible
770          return null;
771        }
772        //we don't creat the array until we have checked
773        //no cycles exist.
774        Object[] topologicalArray = new Object[totalVerticesGraph];
775        topoIndex = 0;
776        Vertex vertex;
777        //Start going through vertices, setting all markers to indegree,
778        //when =0, put into array and sub-seek adjacents, decrementing
779        //simultaneously and recursively putting all who == 0 after decr.
780        for (ListElement n = mainVertexList; n != null; n = n.next) {
781          vertex = (Vertex) n.hangingVertexOrEdge;
782          if (vertex.graphMarker == 0) vertex.graphMarker = vertex.whatIsInDegree();
783          if (vertex.graphMarker == 0) {
784            //after the inDegree is assigned, if this vertex
785            //STILL has 0 (no "dependents") we can call put()
786            putAndDecrement(topologicalArray, vertex);
787          }
788        }
789        clearAllMarkers();
790        return topologicalArray;
791      }
792    
793      /**
794        Helper variable to keep track of topoligical sort
795        array indexing. A global var, passing it around in
796        recursive calls would be very messy.
797       */
798    
799      private int topoIndex;
800    
801      /**
802        A recursive helper method to put found vertex into array,
803        and decrement adjacents. It is necessary to pass the array
804        we are constructing around from method call to method call
805        in order to maximize effectiveness, this way it's not a
806        global variable, in case we don't ever need to create it.
807        @param theArray the array of vertices that we are constructing
808        @param start the vertex where we are starting this sub-call
809       */
810    
811      private void putAndDecrement(Object[] theArray, Vertex start) {
812        //putting the vertex object into the next free spot in array
813        theArray[topoIndex++] = start.vertexObject;
814        //when the vertex has been put into array we mark it with -1
815        start.graphMarker = -1;
816        Edge edge;
817        //now we are going to go through the edge-list and decrement
818        //all the vertex-inDegrees (markers) by one,
819        //and if we decrement any of them to 0, we'll call this
820        //method recursively again to put that vertex into the array
821        //next.
822        for (ListElement i = start.firstEdge; i != null; i = i.next) {
823          edge = (Edge) i.hangingVertexOrEdge;
824          if (edge.targetVertex.graphMarker == 0) {
825            //this is a case where the topologicalSort()
826            //method has not got this far yet, so we need
827            //to do som of its work for it, and mark the inDegree.
828            edge.targetVertex.graphMarker = edge.targetVertex.whatIsInDegree();
829          }
830          //decrementing the adjacent vertex
831          edge.targetVertex.graphMarker--;
832          if (edge.targetVertex.graphMarker == 0) {
833            //if 0, we can now move on through this edge to
834            //put its vertex recursively as well
835            putAndDecrement(theArray, edge.targetVertex);
836          }
837        }
838      }
839    
840      /**
841         Returns <tt>true</tt> if there is a cycle in the directed graph.
842         @return <tt>true</tt> if there is a cycle in the directed graph.
843       */
844    
845     public boolean hasCycle() {
846        cycleStatus = false;
847        Vertex eachVertexInTurn;
848        for (ListElement i = mainVertexList; (i != null) && (cycleStatus != true);i = i.next) {
849          eachVertexInTurn = (Vertex) i.hangingVertexOrEdge;
850          findCycle(eachVertexInTurn);
851          if (cycleStatus) {
852             //newList to add first vertex from which traversing of graph was started
853             ArrayList newList = new ArrayList();
854             newList.add(eachVertexInTurn);
855             newList.addAll(tablesInCycle);
856             tablesInCycle.clear();
857             tablesInCycle.addAll(newList);
858           }
859          clearAllMarkers();
860        }
861        if (cycleStatus == false)return false;
862        return true;
863      }
864    
865      /**
866         Returns <tt>true</tt> if the directed graph forms a linear list. A
867         directed graph with no vertices or one vertex without a self loop is
868         also considered to form a linear list.
869         @return <tt>true</tt> if the directed graph forms a linear list.
870       */
871    
872      public boolean isLinearList() {
873        //we start by checking some obvious
874        //conditions, the simplest ones
875        if (totalVerticesGraph == 0)return true;
876        if (totalVerticesGraph == 1) {
877          //if only one vertex, check for cycle
878          // then return the result and we're done
879          if (EdgesInGraph == 1) {
880            if (hasCycle() == true)return false;
881            return true;
882          }
883        }
884        //after having established the above conditions,
885        //the next obvious sign that it's not a linear list
886        //is if there isn't EXACTLY one less edge than vertices.
887        if (totalVerticesGraph != (EdgesInGraph + 1))return false;
888        //now we start looking for a place to start the checking (in=0)
889        //if at any time we find a vertex with inDegree or outDegree
890        //of more than 1, we can quit and return false
891        Vertex vertex;
892        Vertex startVertex = null;
893        for (ListElement n = mainVertexList; n != null; n = n.next) {
894          vertex = (Vertex) n.hangingVertexOrEdge;
895          if ( (vertex.whatIsInDegree() > 1) || (vertex.whatIsOutDegree() > 1)) {
896            return false;
897          }
898          if (vertex.whatIsInDegree() == 0) {
899            //if this is not the only vertex with in=0, return false
900            if (startVertex != null)return false;
901            startVertex = vertex;
902          }
903        }
904        //now we have a either a link to the "first"
905        //vertex in the supposed linear list,
906        //or then we have a null
907        if (startVertex == null)return false;
908        if (hasCycle() == true)return false;
909        //if all of the above conditions are done,
910        //and we are still here, then our graph is a
911        //linear list
912        return true;
913      }
914    
915    //return ArrayList of tables in cycle
916    public ArrayList TablesInCycle(){
917      return tablesInCycle;
918    }
919    }





























































Powered by Drupal - Theme by Danger4k