All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gr.james.simplegraph.MutableTree Maven / Gradle / Ivy

Go to download

Simple Graph is a graph interface for Java 6 that is designed to expose a very simple API to support working with graphs

The newest version!
package gr.james.simplegraph;

import java.util.Set;

/**
 * The {@link Tree} implementation using adjacency lists.
 */
public class MutableTree implements Tree {
    private static final long serialVersionUID = 1L;

    private final MutableGraph g;

    /**
     * Constructs a new {@link MutableTree} with one unconnected vertex.
     * 

* Complexity: O(1) */ public MutableTree() { this.g = new MutableGraph(1); } /** * Constructs a new {@link MutableTree} as a copy of the given graph {@code g}. *

* Complexity: O(V+E) * * @param g the graph to copy * @throws NullPointerException if {@code g} is {@code null} */ public MutableTree(Tree g) { this.g = new MutableGraph(g); assert g.equals(this); } /** * {@inheritDoc} * * @return {@inheritDoc} */ @Override public int size() { return this.g.size(); } /** * {@inheritDoc} * * @return {@inheritDoc} */ @Override public final int edgeCount() { return size() - 1; } /** * {@inheritDoc} *

Implementation note

* The {@link Set} returned is directly backed by the graph and changes will reflect on that {@link Set}. A side * effect of this property is that the iterator, like any other, will throw * {@link java.util.ConcurrentModificationException} if elements are modified during iteration. * * @param v {@inheritDoc} * @return {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} */ @Override public Set adjacent(int v) { return this.g.adjacent(v); } /** * {@inheritDoc} *

Implementation note

* The {@link Iterable} returned is directly backed by the graph and changes will reflect on that {@link Iterable}. * A side effect of this property is that the iterator, like any other, will throw * {@link java.util.ConcurrentModificationException} if elements are modified during iteration. * * @return {@inheritDoc} */ @Override public final Iterable edges() { return this.g.edges(); } /** * Adds a vertex to the graph and connected it with a given existing vertex. *

* Complexity: O(1) * * @param v the existing vertex with which to connect the new one * @throws IndexOutOfBoundsException if {@code v} is not an existing vertex */ public void addVertex(int v) { this.g.addVertex(); this.g.putEdge(g.size() - 1, v); } /** * Removes a vertex along with all of its edges from the graph. *

* In order to preserve the tree data structure invariants, this method can only remove leaf vertices, that is * vertices with exactly one adherent edge because this is the only way for the graph to remain a tree. The method * will return {@code true} if {@code v} is a leaf vertex and was able to be removed, otherwise will return * {@code false}. *

* This method works in a way that preserves the insertion order of vertices. More specifically, initially all edges * referring to {@code v} are removed, resulting in {@code v} being unconnected. Afterwards, while {@code v} is * removed, all vertices with ID {@code > v} slide one position to the left to occupy the empty slot. Finally, the * {@code size} of the graph is reduced by one. A side effect of this process is that the vertices with ID higher * than {@code v} are mutated to an ID that is lower by one unit. *

* Complexity: O(V+E) * * @param v the vertex to remove from the graph * @return {@code true} if {@code v} was removed from the graph, otherwise {@code false} * @throws IndexOutOfBoundsException if {@code v} is outside of {@code [O,V)} */ public boolean removeVertex(int v) { if (adjacent(v).size() == 1) { this.g.removeVertex(v); return true; } else { return false; } } /** * Construct and return a new unmodifiable {@link Tree} as a copy of this graph. *

* The object produced by this method is completely independent of this graph. *

* This method is equivalent to *


     * return new MutableTree(this).asUnmodifiable();
     * 
*

* Complexity: O(V+E) * * @return a copy of this graph as a new unmodifiable {@link Tree} */ public final Tree toImmutable() { return new MutableTree(this).asUnmodifiable(); } /** * Returns an unmodifiable decorator around this graph. *

* Invoking any mutation methods on the resulting graph will result in {@link UnsupportedOperationException}. *

* Complexity: O(1) * * @return an unmodifiable decorator around this graph */ public final Tree asUnmodifiable() { return new MutableTree() { @Override public int size() { return MutableTree.this.size(); } @Override public Set adjacent(int v) { return MutableTree.this.adjacent(v); } @Override public void addVertex(int v) { throw new UnsupportedOperationException(); } @Override public boolean removeVertex(int v) { throw new UnsupportedOperationException(); } }; } /** * {@inheritDoc} *

Implementation note

* Because there are semantic differences among different types of graphs, some mutation methods in the resulting * graph may be ambiguous when forwarded to this graph. Instead of trying to circumvent these types of restrictions * with unusual or opinionated ways, these methods will immediately throw {@link UnsupportedOperationException}. * * @return {@inheritDoc} */ @Override public final MutableDirectedGraph asDirected() { return new MutableDirectedGraph() { @Override public int size() { return MutableTree.this.size(); } @Override public Set adjacentOut(int v) { return MutableTree.this.adjacent(v); } @Override public Set adjacentIn(int v) { return MutableTree.this.adjacent(v); } @Override public void addVertex() { throw new UnsupportedOperationException(); } @Override public void removeVertex(int v) { if (!MutableTree.this.removeVertex(v)) { throw new UnsupportedOperationException(); } } @Override public boolean putEdge(int source, int target) { throw new UnsupportedOperationException(); } @Override public boolean removeEdge(int source, int target) { throw new UnsupportedOperationException(); } }; } /** * {@inheritDoc} *

Implementation note

* Because there are semantic differences among different types of graphs, some mutation methods in the resulting * graph may be ambiguous when forwarded to this graph. Instead of trying to circumvent these types of restrictions * with unusual or opinionated ways, these methods will immediately throw {@link UnsupportedOperationException}. * * @return {@inheritDoc} */ @Override public final MutableWeightedGraph asWeighted() { return new MutableWeightedGraph() { @Override public int size() { return MutableTree.this.size(); } @Override public Set getEdges(int v) { return MutableTree.this.adjacent(v); } @Override public double getEdgeWeight(int v, int w) { Graphs.requireEdgeExists(MutableTree.this, v, w); return 1.0; } @Override public void addVertex() { throw new UnsupportedOperationException(); } @Override public void removeVertex(int v) { if (!MutableTree.this.removeVertex(v)) { throw new UnsupportedOperationException(); } } @Override public Double putEdge(int v, int w, double weight) { throw new UnsupportedOperationException(); } @Override public Double removeEdge(int v, int w) { throw new UnsupportedOperationException(); } }; } /** * {@inheritDoc} *

Implementation note

* Because there are semantic differences among different types of graphs, some mutation methods in the resulting * graph may be ambiguous when forwarded to this graph. Instead of trying to circumvent these types of restrictions * with unusual or opinionated ways, these methods will immediately throw {@link UnsupportedOperationException}. * * @return {@inheritDoc} */ @Override public final MutableWeightedDirectedGraph asWeightedDirected() { return new MutableWeightedDirectedGraph() { @Override public int size() { return MutableTree.this.size(); } @Override public Set getOutEdges(int v) { return MutableTree.this.adjacent(v); } @Override public Set getInEdges(int v) { return MutableTree.this.adjacent(v); } @Override public double getEdgeWeight(int source, int target) { Graphs.requireEdgeExists(MutableTree.this, source, target); return 1.0; } @Override public void addVertex() { throw new UnsupportedOperationException(); } @Override public void removeVertex(int v) { if (!MutableTree.this.removeVertex(v)) { throw new UnsupportedOperationException(); } } @Override public Double putEdge(int source, int target, double weight) { throw new UnsupportedOperationException(); } @Override public Double removeEdge(int source, int target) { throw new UnsupportedOperationException(); } }; } /** * {@inheritDoc} * * @return {@inheritDoc} */ @Override public final String toString() { final StringBuilder sb = new StringBuilder(); sb.append(String.format("%s(%d) {%n", "Tree", this.size())); for (Edge e : edges()) { sb.append(String.format(" %s%n", e)); } sb.append("}"); return sb.toString(); } /** * {@inheritDoc} * * @param obj {@inheritDoc} * @return {@inheritDoc} */ @Override public final boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || !(obj instanceof Graph)) { return false; } final Graph that = (Graph) obj; return Graphs.equals(this, that); } /** * {@inheritDoc} * * @return {@inheritDoc} */ @Override public final int hashCode() { return this.g.hashCode(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy