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;// Sanitize
for (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();}}
![Creative Commons License](http://i.creativecommons.org/l/by/2.5/cn/88x31.png)
本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名小橋流水(包含链接)。如您有任何疑问或者授权方面的协商,请给我发邮件。