Java 图的Hashmap表示
例如,我有一个带有图形边缘的文本文件 1 2 13 2.5 等等,, 并希望以某种方式表示我的图形。我试着使用hashmap,这是表示边的最好方法吗? 第二个问题,如何访问hashmap中的第一个和第二个条目? 我的代码在这里Java 图的Hashmap表示,java,graph,hashmap,Java,Graph,Hashmap,例如,我有一个带有图形边缘的文本文件 1 2 13 2.5 等等,, 并希望以某种方式表示我的图形。我试着使用hashmap,这是表示边的最好方法吗? 第二个问题,如何访问hashmap中的第一个和第二个条目? 我的代码在这里 DataInputStream dStream = new DataInputStream(new FileInputStream("C:/Programming/Java/test.txt")); BufferedReader bReader = new
DataInputStream dStream = new DataInputStream(new FileInputStream("C:/Programming/Java/test.txt"));
BufferedReader bReader = new BufferedReader(new InputStreamReader(dStream));
HashMap<Integer, Integer> graphEdges = new HashMap<Integer, Integer>();
String line;
while( (line = bReader.readLine()) != null) {
String[] firstSecond = line.split(" ");
int firstDigit = Integer.parseInt(firstSecond[0]);
int secondDigit = Integer.parseInt(firstSecond[1]);
graphEdges.put(firstDigit, secondDigit);
}
System.out.println(graphEdges);
bReader.close();
}
DataInputStream dStream=newdatainputstream(newfileinputstream(“C:/Programming/Java/test.txt”);
BufferedReader bReader=新的BufferedReader(新的InputStreamReader(数据流));
HashMap graphEdges=新HashMap();
弦线;
而((line=bReader.readLine())!=null){
String[]firstSecond=line.split(“”);
int firstDigit=Integer.parseInt(firstSecond[0]);
int secondDigit=Integer.parseInt(firstSecond[1]);
graphEdges.put(第一位数字,第二位数字);
}
System.out.println(图形化);
bReader.close();
}
AHashMap
不适合这种情况,因为对于指定的键,可以有一个值。您需要一个可以为一个键保存多个值的映射。在类似的实现中正好有这个概念。HashMap不是表示边的最佳方式,因为图形遍历不是最优的。遍历N条边的路径需要N个hashmap get()操作。要生成如下PNG:
<?xml version="1.0" encoding="UTF-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<graph id="G" edgedefault="directed">
<node id="Off" />
<node id="Standby" />
<node id="Fail" />
<node id="Oper" />
<node id="Recovery" />
<node id="Shutdown" />
<edge id="1" source="Off" target="Standby" />
<hyperedge>
<endpoint node=Standby" type="in" />
<endpoint node=Fail" type="out" />
<endpoint node=Oper" type="out" />
<endpoint node=Shutdown" type="out" />
</hyperedge>
<hyperedge>
<endpoint node=Fail" type="in" />
<endpoint node=Shutdown" type="out" />
<endpoint node=Recovery" type="out" />
</hyperedge>
<hyperedge>
<endpoint node=Oper" type="in" />
<endpoint node=Standby" type="out" />
<endpoint node=Fail" type="out" />
<endpoint node=Shutdown" type="out" />
</hyperedge>
<edge id="2" source="Shutdown" target="Off" />
<hyperedge>
<endpoint node=Recovery" type="in" />
<endpoint node=Oper" type="out" />
<endpoint node=Shutdown" type="out" />
</hyperedge>
</graph>
</graphml>
或者像这样的XML():
<?xml version="1.0" encoding="UTF-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<graph id="G" edgedefault="directed">
<node id="Off" />
<node id="Standby" />
<node id="Fail" />
<node id="Oper" />
<node id="Recovery" />
<node id="Shutdown" />
<edge id="1" source="Off" target="Standby" />
<hyperedge>
<endpoint node=Standby" type="in" />
<endpoint node=Fail" type="out" />
<endpoint node=Oper" type="out" />
<endpoint node=Shutdown" type="out" />
</hyperedge>
<hyperedge>
<endpoint node=Fail" type="in" />
<endpoint node=Shutdown" type="out" />
<endpoint node=Recovery" type="out" />
</hyperedge>
<hyperedge>
<endpoint node=Oper" type="in" />
<endpoint node=Standby" type="out" />
<endpoint node=Fail" type="out" />
<endpoint node=Shutdown" type="out" />
</hyperedge>
<edge id="2" source="Shutdown" target="Off" />
<hyperedge>
<endpoint node=Recovery" type="in" />
<endpoint node=Oper" type="out" />
<endpoint node=Shutdown" type="out" />
</hyperedge>
</graph>
</graphml>
类定向边缘:
public final class DirectedEdge extends Edge {
private final Node[] _to;
public DirectedEdge( Node from, Node ... to ) {
super( from );
_to = to;
}
public Node getFrom() {
return _endPoint1;
}
public Node[] getTo() {
return _to;
}
}
类图:
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
public final class Graph {
private /* */ String _name = "G";
private final Map< String, Node > _nodes = new LinkedHashMap<>();
private final Set< DirectedEdge > _edges = new LinkedHashSet<>();
public boolean addNode( Node node ) {
return _nodes.put( node._label, node ) == null;
}
public void addEdge( DirectedEdge edge ) {
_edges.add( edge );
}
public String getName() {
return _name;
}
public void setName( String name ) {
_name = name;
}
public final Map<String, Node> getNodes() {
return _nodes;
}
public final Set<DirectedEdge> getEdges() {
return _edges;
}
}
您可以使用列表的地图
HashMap<Integer, LinkedList<Integer>> graphEdges = new HashMap<Integer,LinkedList<Integer>>();
HashMap graphEdges=newhashmap();
通过这种方式,您可以将一个节点映射到多个节点在图形的许多可能表示形式中,以下两种基本表示形式:
- 邻接表
Map<Integer, List<Integer>> graph = new HashMap<>();
...
while( (line = bReader.readLine()) != null) {
String[] tokens = line.split(" ");
int firstNode = Integer.parseInt(tokens[0]);
int secondNode = Integer.parseInt(tokens[1]);
if(!graph.containsKey(firstNode)) graph.put(firstNode, new LinkedList());
graphEdges.get(firstNode).add(secondNode);
}
int[][] graph = new int[numberOfNodes][numberOfNodes];
while( (line = bReader.readLine()) != null) {
String[] tokens = line.split(" ");
int firstNode = Integer.parseInt(tokens[0]);
int secondNode = Integer.parseInt(tokens[1]);
graph[firstNode-1][secondNode-1] = 1;
graph[secondNode-1][firstNode-1] = 1;
}
以下是这两种表示法的操作和存储效率的比较:
| Adjacency List | Adjacency Matrix |
Storage | O(nodes+edges) | O(nodes^2) |
Add node | O(1) | O(nodes^2)* |
Add edge | O(1) | O(1) |
Remove node | O(edges) | O(nodes^2)* |
Remove edge | O(edges) | O(1) |
isAdjacent(x1,x2) | O(nodes) | O(1) |
*Requires copying of the whole array
您还可以在邻接列表中稍作修改,并使用hashset而不是LinkedList来存储相邻节点。在这种情况下,所有操作都是相同的,除了现在具有O(1)复杂性(摊销)的IsAjacent(x1,x2)操作。即使没有番石榴,也可以使用
Map
。@JB Nizet或Map
@JBNizet是的,如果他不能使用第三方库,那么这样的映射(或元组映射或多个映射,取决于他的上下文)是可行的。如答案中所述:这样的映射在这里不合适。你说你想“以某种方式表示我的图形”——你应该在这里更具体一些。大多数图算法的效率(甚至实用性)依赖于在图上执行的一小部分操作。最常见的一个是:“给我顶点X的所有邻居”,或“给我顶点X的所有边”。。。您应该考虑您需要哪些操作,以及哪些结构适合于这些操作(可能是在一个新的、更详细和更集中的问题中),或者使用现有的图形库。您编写的第一个实现表示无向图,对吗?如果是这种情况,上面带有箭头的图像有点模糊misleading@ZenoRaiser好的,谢谢你的帮助。我更新了代码以生成有向图,以避免混淆。
| Adjacency List | Adjacency Matrix |
Storage | O(nodes+edges) | O(nodes^2) |
Add node | O(1) | O(nodes^2)* |
Add edge | O(1) | O(1) |
Remove node | O(edges) | O(nodes^2)* |
Remove edge | O(edges) | O(1) |
isAdjacent(x1,x2) | O(nodes) | O(1) |
*Requires copying of the whole array