SetNoneScaleMutableGraph
WebGraph中的图,基本都会在删除结点后,进行向前移动的操作,其实在很多是侯,这是没有必要的,甚至是有副作用的。SetNoneScaleMutableGraph就是我实现的一个没有进行前移操作的类,还没有做深入的测试,理论上来说,基本没有什么问题。
废话少说,直接上码:
package cn.edu.dlut.wisdom;/** Copyright (C) 2006-2007 Sebastiano Vigna** This program is free software; you can redistribute it and/or modify it* under the terms of the GNU General Public License as published by the Free* Software Foundation; either version 2 of the License, or (at your option)* any later version.** This program is distributed in the hope that it will be useful, but* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License* for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, write to the Free Software* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.**/import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;import it.unimi.dsi.fastutil.ints.IntAVLTreeSet;import it.unimi.dsi.fastutil.ints.IntIterator;import it.unimi.dsi.lang.MutableString;import it.unimi.dsi.webgraph.ImmutableGraph;import it.unimi.dsi.webgraph.LazyIntIterator;import it.unimi.dsi.webgraph.LazyIntIterators;import it.unimi.dsi.webgraph.NodeIterator;import it.unimi.dsi.webgraph.Transform;import java.io.*;/** A very simple mutable graph class based on {@link it.unimi.dsi.fastutil.ints.IntArrayList}s.** <p>When creating examples for test cases or everyday usage, this class offers practical constructors.* For instance, a 3-cycle is easily built as* <pre>* new ArrayListMutableGraph( 3, new int[][] { { 0, 1 }, { 1, 2 }, { 2, 0 } } )* </pre>** <p>Moreover, methods like {@link #addNodes(int)} and {@link #addArc(int, int)} allow to change* the graph structure after construction, and several static factory methods provides ready-made* common graphs (see, e.g., {@link #newCompleteBinaryIntree(int)}).** <p>A mutable graph is <em>not</em> an {@link it.unimi.dsi.webgraph.ImmutableGraph}. However,* it is possible to obtain an {@linkplain #immutableView() immutable view} of a mutable graph.* The view is valid until the exposed mutable graph is modified. A modification counter is used* to cause a <em>fail-fast</em> behaviour in case the immutable view is used after modifications.** <p><strong>Warning</strong>: obtaining a {@link it.unimi.dsi.webgraph.NodeIterator} and using it* while modifying the graph will lead to unpredictable results.*/public class SetNoneScaleMutableGraph extends ImmutableGraph implements Serializable {/** Current number of nodes. */protected int n;/** Current number of arcs. */protected long m;/** Current list of successor lists. The backing array might be longer than {@link #n}. */protected Int2ObjectOpenHashMap<IntAVLTreeSet> successors;/** Guarantees that a node index is valid.** @param x a node index.*/protected void ensureNode(final int x) {if (!successors.containsKey(x)) {throw new IllegalArgumentException("No node " + x);}}/** Creates a new empty mutable graph. */public SetNoneScaleMutableGraph() {successors = new Int2ObjectOpenHashMap<IntAVLTreeSet>();}/** Creates a new mutable graph using a given number of nodes and a given list of arcs.** @param numNodes the number of nodes in the graph.* @param arc an array of arrays of length 2, specifying the arcs; no sanity checks are performed..*/public SetNoneScaleMutableGraph(final int numNodes, final int[][] arc) {n = numNodes;m = arc.length;// Sanitizefor (int i = arc.length; i-- != 0;) {if (arc[i].length != 2) {throw new IllegalArgumentException("The arc of index " + i + " has length " + arc[i].length);}if (arc[i][ 0] < 0 || arc[i][ 1] < 0 || arc[i][ 0] >= numNodes || arc[i][ 1] >= numNodes) {throw new IllegalArgumentException("The arc of index " + i + " (" + arc[i][ 0] + ", " + arc[i][ 1] + ") is illegal");}}successors = new Int2ObjectOpenHashMap<IntAVLTreeSet>();for (int i = 0; i < n; i++) {successors.put(i, new IntAVLTreeSet());}for (int i = 0; i < arc.length; i++) {successors.get(arc[i][ 0]).add(arc[i][ 1]);}}public SetNoneScaleMutableGraph(final int numNodes) {this(numNodes, new int[][]{});}/** Creates a new mutable graph copying a given immutable graph.** @param g an immutable graph.*/public SetNoneScaleMutableGraph(final ImmutableGraph g) {successors = new Int2ObjectOpenHashMap<IntAVLTreeSet>();int d, s = -1;long numArcs = 0;for (NodeIterator nodeIterator = g.nodeIterator(); nodeIterator.hasNext();) {s = nodeIterator.nextInt();d = nodeIterator.outdegree();numArcs += d;successors.put(s, new IntAVLTreeSet(nodeIterator.successorArray(), 0, d));}n = s + 1;m = numArcs;}/** Creates a new mutable graph using a given number of nodes and a given arc filter.** @param numNodes the number of nodes in the graph.* @param arcFilter an arc filter which will specify which arcs go into the graph.*/public SetNoneScaleMutableGraph(final int numNodes, final Transform.ArcFilter arcFilter) {n = numNodes;successors = new Int2ObjectOpenHashMap<IntAVLTreeSet>();for (int i = n; i-- != 0;) {successors.put(i, new IntAVLTreeSet());for (int j = 0; j < n; j++) {if (arcFilter.accept(i, j)) {successors.get(i).add(j);m++;}}}}/** Returns a new mutable graph containing a directed cycle.** @param numNodes the number of nodes in the cycle.*/public static SetNoneScaleMutableGraph newDirectedCycle(final int numNodes) {return new SetNoneScaleMutableGraph(numNodes, new Transform.ArcFilter() {public boolean accept(final int i, final int j) {return (i + 1) % numNodes == j;}});}/** Returns a new mutable graph containing a bidirectional cycle.** @param numNodes the number of nodes in the cycle.*/public static SetNoneScaleMutableGraph newBidirectionalCycle(final int numNodes) {return new SetNoneScaleMutableGraph(numNodes, new Transform.ArcFilter() {public boolean accept(final int i, final int j) {return (i + 1) % numNodes == j || (j + 1) % numNodes == i;}});}/** Returns a new mutable graph containing a complete graph.** @param numNodes the number of nodes in the graph.* @param loops true if you want loops, too.*/public static SetNoneScaleMutableGraph newCompleteGraph(final int numNodes, final boolean loops) {return new SetNoneScaleMutableGraph(numNodes, new Transform.ArcFilter() {public boolean accept(final int i, final int j) {return i != j || loops;}});}/** Returns a new mutable graph containing a complete binary in-tree of given height.** <strong>Warning</strong>: starting from version 1.7, the spurious loop* at the root has been removed.** @param height the height of the tree (0 for the root only).*/public static SetNoneScaleMutableGraph newCompleteBinaryIntree(final int height) {return new SetNoneScaleMutableGraph((1 << (height + 1)) - 1, new Transform.ArcFilter() {public boolean accept(final int i, final int j) {return i != j && i / 2 == j;}});}/** Returns a new mutable graph containing a complete binary out-tree of given height.** <strong>Warning</strong>: starting from version 1.7, the spurious loop* at the root has been removed.** @param height the height of the tree (0 for the root only).*/public static SetNoneScaleMutableGraph newCompleteBinaryOuttree(final int height) {return new SetNoneScaleMutableGraph((1 << (height + 1)) - 1, new Transform.ArcFilter() {public boolean accept(final int i, final int j) {return i != j && j / 2 == i;}});}@Overridepublic int numNodes() {return n;}@Overridepublic int outdegree(final int x) {ensureNode(x);return successors.get(x).size();}@Overridepublic long numArcs() {return m;}@Overridepublic int[] successorArray(final int x) {ensureNode(x);return successors.get(x).toIntArray();}@Overridepublic LazyIntIterator successors(final int x) {ensureNode(x);return LazyIntIterators.lazy(successors.get(x).iterator());}@Overridepublic NodeIterator nodeIterator() {final IntIterator it = successors.keySet().iterator();return new NodeIterator() {int x;@Overridepublic int outdegree() {throw new UnsupportedOperationException("Not supported yet.");}@Overridepublic LazyIntIterator successors() {return LazyIntIterators.lazy(successors.get(x).iterator());}@Overridepublic int[] successorArray() {return successors.get(x).toIntArray();}@Overridepublic boolean hasNext() {return it.hasNext();}@Overridepublic Integer next() {return x = it.next();}@Overridepublic int nextInt() {return x = it.nextInt();}@Override@SuppressWarnings("empty-statement")public int skip(int n) {int i;for (i = 0; i < n && hasNext(); i++, next());return i;}@Overridepublic void remove() throws UnsupportedOperationException {SetNoneScaleMutableGraph.this.removeNode(x);}};}/** Adds the given number of nodes, numbering them from {@link #numNodes()} onwards. The new nodes have no successors.** @param numNewNodes the number of new nodes.*/public void addNodes(final int x) {ensureNoneNode(x);successors.put(x, new IntAVLTreeSet());n++;}public void ensureNoneNode(final int x) {if (successors.containsKey(x)) {throw new IllegalArgumentException("Node " + x + "is already in the Graph");}}/** Removes the given node. All arcs incident on the node are removed, too.** @param x the node to be removed.*/public void removeNode(final int x) {ensureNode(x);m -= successors.get(x).size();successors.remove(x);n--;for (IntAVLTreeSet i : successors.values()) {if (i.contains(x)) {i.remove(x);m--;}}}/** Adds the given arc.** @param x the start of the arc.* @param y the end of the arc.*/public void addArc(final int x, final int y) {ensureNode(x);ensureNode(y);if (successors.get(x).contains(y)) {return;}successors.get(x).add(y);m++;}/** Removes the given arc.** @param x the start of the arc.* @param y the end of the arc.*/public void removeArc(final int x, final int y) {ensureNode(x);ensureNode(y);if (!successors.get(x).contains(y)) {return;}successors.get(x).remove(y);m--;}/** Compare this mutable graph to another object.** @return true iff the given object is a mutable graph the same size, and* the successor list of every node of this graph is equal to the successor list of the corresponding node of <code>o</code>.*/@Overridepublic boolean equals(final Object o) {if (!(o instanceof SetNoneScaleMutableGraph)) {return false;}final SetNoneScaleMutableGraph g = (SetNoneScaleMutableGraph) o;int n = numNodes();if (n != g.numNodes()) {return false;}int[] s, t;int d;while (n-- != 0) {if ((d = outdegree(n)) != g.outdegree(n)) {return false;}s = successorArray(n);t = g.successorArray(n);while (d-- != 0) {if (s[d] != t[d]) {return false;}}}return true;}/** Returns a hash code for this mutable graph.** @return a hash code for this mutable graph.*/@Overridepublic int hashCode() {int n = numNodes(), h = -1;int[] s;int d;for (int i = 0; i < n; i++) {h = h * 31 + i;s = successorArray(i);d = outdegree(i);while (d-- != 0) {h = h * 31 + s[d];}}return h;}@Overridepublic String toString() {MutableString ms = new MutableString();IntIterator ii;ms.append("Nodes: " + numNodes() + " Arcs: " + numArcs() + " ");for (int i = 0; i < numNodes(); i++) {ms.append("Successors of " + i + " (degree " + outdegree(i) + "):");ii = successors.get(i).iterator();while (ii.hasNext()) {ms.append(" " + ii.nextInt());}ms.append(" ");}return ms.toString();}@Overridepublic ImmutableGraph copy() {return this;}@Overridepublic boolean randomAccess() {return true;}/*** @param basename end with .sg* @return* @throws IOException*/public static SetNoneScaleMutableGraph load(CharSequence basename)throws IOException {ObjectInputStream oi = new ObjectInputStream(new FileInputStream(basename + ".sg"));SetNoneScaleMutableGraph sg;try {sg = (SetNoneScaleMutableGraph) oi.readObject();} catch (ClassNotFoundException ex) {sg = null;}oi.close();return sg;}public static void store(SetNoneScaleMutableGraph sg, CharSequence basename) throws IOException {ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(basename + ".sg"));oo.writeObject(sg);oo.flush();oo.close();}}
本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名小橋流水(包含链接)。如您有任何疑问或者授权方面的协商,请给我发邮件。
浙公网安备 33010602011771号