Skip to content

Commit e11bfe4

Browse files
author
Rodion Efremov
committed
Initial commit. Testing UndirectedGraph.
0 parents  commit e11bfe4

File tree

5 files changed

+473
-0
lines changed

5 files changed

+473
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
target

pom.xml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<groupId>net.coderodde.graph</groupId>
5+
<artifactId>GraphDatastruct</artifactId>
6+
<version>1.6</version>
7+
<packaging>jar</packaging>
8+
<dependencies>
9+
<dependency>
10+
<groupId>junit</groupId>
11+
<artifactId>junit</artifactId>
12+
<version>4.10</version>
13+
<scope>test</scope>
14+
</dependency>
15+
</dependencies>
16+
<properties>
17+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
18+
<maven.compiler.source>1.7</maven.compiler.source>
19+
<maven.compiler.target>1.7</maven.compiler.target>
20+
</properties>
21+
</project>
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package net.coderodde.graph;
2+
3+
import java.util.Set;
4+
5+
/**
6+
* This class defines the API for graph data structures. The actual nodes are
7+
* represented as integers. The client programmer should always be able to map
8+
* his domain specific nodes to the integers.
9+
*
10+
* @author Rodion "rodde" Efremov
11+
* @version 1.6 (Jan 10, 2016)
12+
*/
13+
public abstract class AbstractGraph {
14+
15+
protected int edges;
16+
17+
/**
18+
* Returns the number of nodes in this graph.
19+
*
20+
* @return the size of this graph.
21+
*/
22+
public abstract int size();
23+
24+
/**
25+
* Returns the number of edges in this graph.
26+
*
27+
* @return the number of edges.
28+
*/
29+
public abstract int getNumberOfEdges();
30+
31+
/**
32+
* Adds the node with ID {@code nodeId} to this graph.
33+
*
34+
* @param nodeId the ID of the node to add.
35+
* @return {@code true} if the structure of this graph has changed, which is
36+
* the same as that the added node was not present in the graph.
37+
*/
38+
public abstract boolean addNode(int nodeId);
39+
40+
/**
41+
* Checks whether the given node is present in this graph.
42+
*
43+
* @param nodeId the query node.
44+
* @return {@code true} if the query node is in this graph. {@code false} 
45+
* otherwise.
46+
*/
47+
public abstract boolean hasNode(int nodeId);
48+
49+
/**
50+
* Removes the argument node from this graph.
51+
*
52+
* @param nodeId the node to remove.
53+
* @return {@code true} only if the node was present in the graph which
54+
* means that the structure of the graph has changed.
55+
*/
56+
public abstract boolean removeNode(int nodeId);
57+
58+
/**
59+
* Creates an edge between {@code tailNodeId} and {@code headNodeId} with
60+
* weight {@code weight}. It depends on the concrete implementation of this
61+
* abstract class what an edge {@code (tailNodeId, headNodeId)}. Two
62+
* possible cases are an undirected edge and a directed edge. Refer to the
63+
* documentation of the implementing graph type.
64+
* <p>
65+
* If some of the input nodes are not present in this graph, it will be
66+
* created silently.
67+
*
68+
* @param tailNodeId the tail node of the edge.
69+
* @param headNodeId the head node of the edge.
70+
* @param weight the weight of the edge.
71+
* @return {@code true} only if the edge was not present in the graph, or
72+
* the weight of the edge has changed.
73+
*/
74+
public abstract boolean addEdge(int tailNodeId,
75+
int headNodeId,
76+
double weight);
77+
78+
/**
79+
* Creates an edge between {@code tailNodeId} and {@code headNodeId} with
80+
* the default weight of 1.0. This method is a shortcut for constructing
81+
* (virtually) unweighted graphs.
82+
*
83+
* @param tailNodeId the tail node of the edge.
84+
* @param headNodeId the head node of the edge.
85+
* @return {@code true}  only if the edge was not present in the graph, or
86+
* the weight of the edge has changed.
87+
*/
88+
public boolean addEdge(int tailNodeId, int headNodeId) {
89+
return addEdge(tailNodeId, headNodeId, 1.0);
90+
}
91+
92+
/**
93+
* Returns a boolean value indicating whether this graph contains an edge
94+
* from {@code tailNodeId} to {@code headNodeId}.
95+
*
96+
* @param tailNodeId the tail node of the query edge.
97+
* @param headNodeId the head node of the query edge.
98+
* @return {@code true} only if the query edge is in this graph.
99+
*/
100+
public abstract boolean hasEdge(int tailNodeId, int headNodeId);
101+
102+
/**
103+
* Returns the weight of the edge {@code (tailNodeId, headNodeId)}. If the
104+
* query edge does not exist, returns {@link java.lang.Double#NaN}.
105+
*
106+
* @param tailNodeId the tail node of the query edge.
107+
* @param headNodeId the head node of the query edge.
108+
* @return the weight of the edge.
109+
*/
110+
public abstract double getEdgeWeight(int tailNodeId, int headNodeId);
111+
112+
/**
113+
* Removes the edge from {@code tailNodeId} and {@code headNodeId}.
114+
*
115+
* @param tailNodeId the tail node of the edge to remove.
116+
* @param headNodeId the head node of the edge to remove.
117+
* @return {@code true} if the target edge was in this graph, and thus is
118+
* removed.
119+
*/
120+
public abstract boolean removeEdge(int tailNodeId, int headNodeId);
121+
122+
/**
123+
* Returns the set of all nodes that are children of the node
124+
* {@code nodeId}. It depends on the actual graph implementation what is
125+
* understood by the termin <i>child</i>. In unweighted graphs, every child
126+
* is also a parent of a node, which is not necessarily true in directed
127+
* graphs.
128+
*
129+
* @param nodeId the query node.
130+
* @return set of nodes that are children on the argument node.
131+
*/
132+
public abstract Set<Integer> getChildrenOf(int nodeId);
133+
134+
/**
135+
* Returns the set of all nodes that are parents of the node {@code nodeId}.
136+
*
137+
* @see #getChildrenOf(int)
138+
* @param nodeId the query node.
139+
* @return set of nodes that are parent of the arugment node.
140+
*/
141+
public abstract Set<Integer> getParentsOf(int nodeId);
142+
143+
/**
144+
* Returns the set of all nodes stored in this graph.
145+
*
146+
* @return the set of all nodes.
147+
*/
148+
public abstract Set<Integer> getAllNodes();
149+
150+
/**
151+
* Removes all nodes and edges from this graph.
152+
*/
153+
public abstract void clear();
154+
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package net.coderodde.graph;
2+
3+
import java.util.Collections;
4+
import java.util.LinkedHashMap;
5+
import java.util.Map;
6+
import java.util.Set;
7+
8+
/**
9+
* This class implements an undirected graph.
10+
*
11+
* @author Rodion "rodde" Efremov
12+
* @version 1.6 (Jan 10, 2016)
13+
*/
14+
public class UndirectedGraph extends AbstractGraph {
15+
16+
private final Map<Integer, Map<Integer, Double>> map =
17+
new LinkedHashMap<>();
18+
19+
@Override
20+
public int size() {
21+
return map.size();
22+
}
23+
24+
@Override
25+
public int getNumberOfEdges() {
26+
return edges;
27+
}
28+
29+
@Override
30+
public boolean addNode(int nodeId) {
31+
if (map.containsKey(nodeId)) {
32+
return false;
33+
}
34+
35+
map.put(nodeId, new LinkedHashMap<Integer, Double>());
36+
return true;
37+
}
38+
39+
@Override
40+
public boolean hasNode(int nodeId) {
41+
return map.containsKey(nodeId);
42+
}
43+
44+
@Override
45+
public boolean removeNode(int nodeId) {
46+
if (!map.containsKey(nodeId)) {
47+
return false;
48+
}
49+
50+
Map<Integer, Double> neighbors = map.get(nodeId);
51+
52+
for (Integer neighborId : neighbors.keySet()) {
53+
map.get(neighborId).remove(nodeId);
54+
}
55+
56+
map.remove(nodeId);
57+
return true;
58+
}
59+
60+
@Override
61+
public boolean addEdge(int tailNodeId, int headNodeId, double weight) {
62+
addNode(tailNodeId);
63+
addNode(headNodeId);
64+
65+
if (!map.get(tailNodeId).containsKey(headNodeId)) {
66+
map.get(tailNodeId).put(headNodeId, weight);
67+
map.get(headNodeId).put(tailNodeId, weight);
68+
++edges;
69+
return true;
70+
} else {
71+
double oldWeight = map.get(tailNodeId).get(headNodeId);
72+
map.get(tailNodeId).put(headNodeId, weight);
73+
map.get(headNodeId).put(tailNodeId, weight);
74+
return oldWeight != weight;
75+
}
76+
}
77+
78+
@Override
79+
public boolean hasEdge(int tailNodeId, int headNodeId) {
80+
if (!map.containsKey(tailNodeId)) {
81+
return false;
82+
}
83+
84+
return map.get(tailNodeId).containsKey(headNodeId);
85+
}
86+
87+
@Override
88+
public double getEdgeWeight(int tailNodeId, int headNodeId) {
89+
if (!hasEdge(tailNodeId, headNodeId)) {
90+
return Double.NaN;
91+
}
92+
93+
return map.get(tailNodeId).get(headNodeId);
94+
}
95+
96+
@Override
97+
public boolean removeEdge(int tailNodeId, int headNodeId) {
98+
if (!map.containsKey(tailNodeId)) {
99+
return false;
100+
}
101+
102+
if (!map.get(tailNodeId).containsKey(headNodeId)) {
103+
return false;
104+
}
105+
106+
map.get(tailNodeId).remove(headNodeId);
107+
map.get(headNodeId).remove(tailNodeId);
108+
--edges;
109+
return true;
110+
}
111+
112+
@Override
113+
public Set<Integer> getChildrenOf(int nodeId) {
114+
if (!map.containsKey(nodeId)) {
115+
return Collections.<Integer>emptySet();
116+
}
117+
118+
return Collections.<Integer>unmodifiableSet(map.get(nodeId).keySet());
119+
}
120+
121+
@Override
122+
public Set<Integer> getParentsOf(int nodeId) {
123+
if (!map.containsKey(nodeId)) {
124+
return Collections.<Integer>emptySet();
125+
}
126+
127+
return Collections.<Integer>unmodifiableSet(map.get(nodeId).keySet());
128+
}
129+
130+
@Override
131+
public Set<Integer> getAllNodes() {
132+
return Collections.<Integer>unmodifiableSet(map.keySet());
133+
}
134+
135+
@Override
136+
public void clear() {
137+
map.clear();
138+
edges = 0;
139+
}
140+
}

0 commit comments

Comments
 (0)