-
Notifications
You must be signed in to change notification settings - Fork 0
/
DirectedSparseGraph.java
141 lines (105 loc) · 3.75 KB
/
DirectedSparseGraph.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package com.sleepycoders.jlib.datastructure.graph;
import java.util.*;
/**
* @author Joshua Moody ([email protected])
*/
public class DirectedSparseGraph<TVertex> implements IGraph<TVertex> {
final TVertex EMPTY_VERTEX_SLOT = null;
int vertexCapacity;
int vertexCount;
public int vertexCount() {
return vertexCount;
}
int edgeCount;
public int edgeCount() { return edgeCount; }
List<TVertex> vertices;
Map<TVertex, List<TVertex>> edges;
public DirectedSparseGraph(int capacity) {
vertexCapacity = capacity;
vertexCount = 0;
edgeCount = 0;
edges = new HashMap<TVertex, List<TVertex>>(capacity);
vertices = new ArrayList<TVertex>(capacity);
for (int i = 0; i < vertexCapacity; i++) {
vertices.add(EMPTY_VERTEX_SLOT);
}
}
// Vertices
public boolean containsVertex(TVertex v) {
return containsVertex(vertices.indexOf(v));
}
private boolean containsVertex(int v) {
return v != -1 && vertices.get(v) != EMPTY_VERTEX_SLOT;
}
public boolean addVertex(TVertex v) {
// is their space in the graph?
if (vertexCount >= vertexCapacity) { return false; }
// does the graph already contain this vertex?
if (containsVertex(v)) { return false; }
// find a free spot
int freeIndex = vertices.indexOf(EMPTY_VERTEX_SLOT);
vertices.set(freeIndex, v);
edges.put(v, new LinkedList<TVertex>());
vertexCount++;
return true;
}
public boolean removeVertex(TVertex v) {
// is the graph empty?
if (vertexCount == 0) { return false; }
// lazily remove vertex
int index = vertices.indexOf(v);
if (index == -1) { return false; }
vertices.set(index, EMPTY_VERTEX_SLOT);
vertexCount--;
// remove outgoing and incoming edges
edgeCount -= edges.remove(v).size();
for ( List<TVertex> incoming : edges.values()) {
if (incoming.remove(v)) { edgeCount--; }
}
return true;
}
public boolean containsEdge(TVertex src, TVertex dst) {
return edges.containsKey(src) && edges.get(src).contains(dst);
}
public boolean addEdge(TVertex src, TVertex dst) {
// are these nodes of the graph?
if (!containsVertex(src) || !containsVertex(dst)) { return false; }
// graph already contains edge
if (containsEdge(src, dst)) { return false; }
// add the new edge
edges.get(src).add(dst);
edgeCount++;
return true;
}
public boolean removeEdge(TVertex src, TVertex dst) {
// are these nodes of the graph?
if (!containsVertex(src) || !containsVertex(dst)) { return false; }
// graph already contains edge
if (!containsEdge(src, dst)) { return false; }
edges.get(src).remove(dst);
edgeCount--;
return true;
}
public List<TVertex> neighbours(TVertex src) {
List<TVertex> destinations = new ArrayList<TVertex>();
if (containsVertex(src)) { destinations.addAll(edges.get(src)); }
return destinations;
}
/**
* @return a human-readable string of the graph.
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (TVertex src : vertices) {
// source vertex
if (src == EMPTY_VERTEX_SLOT) { continue; }
sb.append("\r\n").append(src).append(": [");
// add destinations
for (TVertex dst : neighbours(src)) { sb.append(dst).append(','); }
if (sb.charAt(sb.length() - 1) == ',') { sb.deleteCharAt(sb.length() - 1); }
sb.append("]");
}
return sb.toString();
}
}