00001
package com.quadcap.util.collections;
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
import java.util.ArrayList;
00051
import java.util.HashMap;
00052
import java.util.HashSet;
00053
import java.util.Iterator;
00054
import java.util.Map;
00055
import java.util.Set;
00056
00057
00058
import com.quadcap.util.Debug;
00059
00060
00061
00062
00063
00064
00065
00066 public class DiGraph {
00067
00068 final HashMap
nodes =
new HashMap();
00069
00070 public DiGraph() {}
00071
00072 public void addNode(Object obj) {
00073
mapNode(obj);
00074 }
00075
00076 public final Iterator
getNodes() {
00077
return new NodeIterator(
nodes.values().iterator());
00078 }
00079
00080 public void addArc(Object from, Object to) {
00081
Node f =
mapNode(from);
00082
Node t = mapNode(to);
00083 f.
addTo(t);
00084 t.
addFrom(f);
00085 }
00086
00087 public final boolean hasChildren(Object obj) {
00088
return mapNode(obj).
toSize() > 0;
00089 }
00090
00091 public final boolean hasParents(Object obj) {
00092
return mapNode(obj).
fromSize() > 0;
00093 }
00094
00095 public boolean hasNode(Object obj) {
00096
Node node = (
Node)
nodes.get(obj);
00097
return node != null;
00098 }
00099
00100 public final Iterator
getParents(Object to) {
00101
return new NodeIterator(
mapNode(to).iterateFrom());
00102 }
00103
00104 public final Iterator
getChildren(Object from) {
00105
return new NodeIterator(
mapNode(from).iterateTo());
00106 }
00107
00108 public void removeNode(Object obj,
boolean force) {
00109
Node node =
mapNode(obj);
00110
if (!force) {
00111
if (node.
toSize() != 0 || node.
fromSize() != 0) {
00112
throw new RuntimeException(
"node has links");
00113 }
00114 }
else {
00115 Iterator iter = node.
iterateTo();
00116
while (iter.hasNext()) {
00117
Node to = (
Node)iter.next();
00118 node.
removeTo(to);
00119 to.
removeFrom(node);
00120 }
00121 iter = node.
iterateFrom();
00122
while (iter.hasNext()) {
00123
Node from = (
Node)iter.next();
00124 node.
removeFrom(from);
00125 from.
removeTo(node);
00126 }
00127 }
00128
nodes.remove(obj);
00129 }
00130
00131 public void removeArc(Object from, Object to) {
00132
Node f =
mapNode(from);
00133
Node t = mapNode(to);
00134 f.
removeTo(t);
00135 t.
removeFrom(f);
00136 }
00137
00138 public Iterator
levelize() {
00139
return levelize(
false);
00140 }
00141
00142 public Iterator
levelize(
boolean cyclesOK) {
00143 ArrayList v =
new ArrayList();
00144 Iterator iter =
nodes.values().iterator();
00145
while (iter.hasNext()) {
00146
Node node = (
Node)iter.next();
00147 node.
level = -1;
00148 node.
visitCnt = 0;
00149
if (node.
fromSize() == 0) {
00150 node.
level = 0;
00151 v.add(node);
00152 }
00153 }
00154
for (
int i = 0; i < v.size(); i++) {
00155
Node node = (
Node)v.get(i);
00156 Iterator t = node.
iterateTo();
00157
while (t.hasNext()) {
00158
Node to = (
Node)t.next();
00159
if (++to.
visitCnt == to.
fromSize()) {
00160 to.
level = node.
level + 1;
00161 v.add(to);
00162 }
00163 }
00164 }
00165
if (!cyclesOK && v.size() !=
nodes.size()) {
00166
throw new RuntimeException(
"can't levelize, contains cycles");
00167 }
00168
return new NodeIterator(v.iterator());
00169 }
00170
00171 public String
toString() {
00172 StringBuffer sb =
new StringBuffer();
00173 Iterator iter =
getNodes();
00174 String ldelim =
"";
00175
while (iter.hasNext()) {
00176 sb.append(ldelim);
00177 ldelim =
"\n";
00178 Object obj = iter.next();
00179 Iterator i2 = getParents(obj);
00180 String delim =
"";
00181 sb.append(
"(");
00182
while (i2.hasNext()) {
00183 sb.append(delim);
00184 delim =
" ";
00185 sb.append(i2.next().toString());
00186 }
00187 sb.append(
") ");
00188 sb.append(obj.toString());
00189 sb.append(
" (");
00190 i2 = getChildren(obj);
00191 delim =
"";
00192
while (i2.hasNext()) {
00193 sb.append(delim);
00194 delim =
" ";
00195 sb.append(i2.next().toString());
00196 }
00197 sb.append(
") ");
00198 }
00199
return sb.toString();
00200 }
00201
00202 final Node mapNode(Object obj) {
00203
Node node = (
Node)
nodes.get(obj);
00204
if (node == null) {
00205 node =
new Node(obj);
00206
nodes.put(obj, node);
00207 }
00208
return node;
00209 }
00210
00211 class Node implements Comparable {
00212 Object
obj;
00213
00214 final HashSet
to =
new HashSet();
00215 final HashSet
from =
new HashSet();
00216 int level = 0;
00217 int visitCnt = 0;
00218
00219 Node(Object obj) {
this.obj = obj; }
00220 void addTo(
Node node) {
00221
to.add(node);
00222 }
00223 void addFrom(
Node node) {
00224
from.add(node);
00225 }
00226 void removeTo(
Node obj) {
to.remove(obj); }
00227 void removeFrom(
Node obj) {
from.remove(obj); }
00228
00229 int toSize() {
return to.size(); }
00230 int fromSize() {
return from.size(); }
00231
00232 Iterator
iterateTo() {
return to.iterator(); }
00233 Iterator
iterateFrom() {
return from.iterator(); }
00234
00235 public int compareTo(Object other) {
00236
Node no = (
Node)other;
00237
return ((
Comparable)
obj).compareTo(no.
obj);
00238 }
00239
00240 public int hashCode() {
return obj.hashCode(); }
00241
00242 public boolean equals(Object obj) {
00243
return 0 == compareTo(obj);
00244 }
00245 public String
toString() {
00246
return obj.toString();
00247 }
00248 }
00249
00250 class NodeIterator implements Iterator {
00251 Iterator
iter;
00252 NodeIterator(Iterator iter) {
this.iter = iter; }
00253 public boolean hasNext() {
return iter.hasNext(); }
00254 public Object
next() {
00255
Node node = (
Node)
iter.next();
00256
return node.
obj;
00257 }
00258 public void remove() {}
00259 }
00260 }
00261