我有一个Location POJO,用于存储从JSON文件解析的Location对象,我想将其映射到图形。图中每个节点的位置对应于它的id字段,其中id =“1”是起始节点,id =“10”是目标节点。
为了解决这个问题,我调整了一个Node类,以包含setWeight()
,addChildLocation()
等方法,但我不确定如何从我的位置列表中创建图形。我知道如何通过硬编码位置和调用addChildren来创建图形,通过执行以下操作,但不知道如何从已有的Location对象列表创建它:
Node LocationOne= new Node("LocationOne", 170);
LocationOne.addChildNode(LocationTwo, 105);
我对这个问题的看法是,应该使用for..each
循环遍历列表中的位置,并将每个位置添加为前一个位置的子项。
基本上,我想知道如何迭代Location对象列表,并在每个连续位置调用addChild?
下面是我用来将位置映射到对象表示的Location类:
public class Location {
private Location[] location;
private int id;
private String description;
private String weight;
private String name;
private Exit[] exit;
private boolean visited = false;
private boolean goalLocation;
private int approximateDistanceFromGoal = 0;
private Location parent;
private Map<Location, Integer> children = new HashMap<Location, Integer>();
public Location() {
super();
}
public Location(String name){
this.name = name;
}
public Location(String name, int goalDistance){
this.name = name;
this.approximateDistanceFromGoal = goalDistance;
}
public Location[] children(){
return (Location[]) children.keySet().toArray(new Location[children.size()]);
}
public int getDistance(Location loc){
if(children.get(loc) == null) System.out.println(this.name + ": " + loc.getName());
return children.get(loc);
}
public int getChildLocationCount(){
return children.size();
}
public void addChildLocation(Location child, int distance){
children.put(child, distance);
}
public boolean isLeaf(){
if (children.size() > 0){
return false;
}else{
return true;
}
}
public void removeChild(Location child){
children.remove(child);
}
public Location[] getLocation() {
return location;
}
public void setLocation(Location[] location) {
this.location = location;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDescription ()
{
return description;
}
public void setDescription (String description)
{
this.description = description;
}
public String getWeight() {
return weight;
}
public void setWeight(String weight) {
this.weight = weight;
}
public String getName ()
{
return name;
}
public void setName (String name)
{
this.name = name;
}
public Exit[] getExit() {
return exit;
}
public void setExit(Exit[] exit) {
this.exit = exit;
}
public boolean isVisited() {
return visited;
}
public void setVisited(boolean visited) {
this.visited = visited;
}
public boolean isGoalLocation() {
return goalLocation;
}
public void setGoalLocation(boolean goalLocation) {
this.goalLocation = goalLocation;
}
public int getApproximateDistanceFromGoal() {
return approximateDistanceFromGoal;
}
public void setApproximateDistanceFromGoal(int approximateDistanceFromGoal) {
this.approximateDistanceFromGoal = approximateDistanceFromGoal;
}
public Location getParent() {
return parent;
}
public void setParent(Location parent) {
this.parent = parent;
}
@Override
public String toString() {
return "Location [location=" + Arrays.toString(location) + ", id=" + id
+ ", description=" + description + ", weight=" + weight
+ ", name=" + name + ", exit=" + Arrays.toString(exit)
+"]";
}
}
答案 0 :(得分:3)
如果你想构建任何类型的图形,那么要认识到图形由2个基本元素组成:
关键属性:
实际上,您如何访问这些将取决于功能和性能之间的权衡。此外,如果图形节点不包含您的某些信息,则它们毫无价值。所以,我们添加
Map<String,Object> properties
因此我们可以存储一些数据:
new Vertext().set("age",10);
我们还使用命名边缘,因此您可以执行以下操作:
Graph g = new Graph();
g.addVertex("Doctor",new DrVertex("Dr. Smith"));
g.addVertex("Doctor",new DrVertex("Dr. Cooper"));
List<Vertex> doctors = g.get("Doctor");
assertTrue("Dr. Smith",doctors.get(0));
assertTrue("Dr. Cooper",doctors.get(1));
我已经将我如何实现通用图的基本结构放在一起。但有些人指出,像Neo这样的图形数据库非常复杂。
以下是代码。如果您想为您的位置建模,请使用它。
/**
* @author Christian Bongiorno
*/
public class Graph {
private class Vertex {
Map<String,Object> properties;
private Map<String,Edge> edges;
public Graph addVertex(String edgeName, Vertex v) {
Edge e = edges.get(edgeName);
if(e == null) {
e = new Edge(this);
edges.put(edgeName,e);
}
e.addVertex(v);
return Graph.this;
}
public Graph addVertex(Vertex v) {
return addVertex("anonymous",v);
}
}
private static class Edge {
Map<String,Object> properties;
Vertex in;
Collection<Vertex> out;
private Edge(Vertex in) {
this.in = in;
}
private void addVertex(Vertex v) {
out.add(v);
}
}
}
您可以考虑将此问题移至codereview.stackexchange.com
被修改
想象一下你的代码是这样的:
您的代码很难处理,因为您没有声明边缘。边缘的一个特性是'#34; weight&#34;但在这里你把它作为地点的财产。
至于实施&#34;访问&#34; - 这是一个呼叫状态,而不是图宽状态。但是,通过使其成为位置的一部分,您现在遇到了州管理问题;想象一下,试图找到&#34;再一次?你必须重置“访问过的”#39;每个节点上的属性或丢弃并再次创建整个图形。非常低效且容易出错。
如果你实现DFS,这很容易递归,甚至是尾循环,你可以通过&#34;访问过的&#34;状态以及dfs方法调用。例如:
public Location find(Integer locationId) {
Location result = null;
for(Location l : locations) {
// this hashset represents the visited state which only matters for this method call
result = dfs(new HashSet(),l,locationId);
if(result != null)
break;
}
return result;
}
请注意,下一个方法是私有。
private Location dfs(Set<Location> visitedAlready,Location current, Integer id){
if(current.id == id)
return current;
visitedAlready.add(current); // instead of your boolean
Location result = null;
for(Location l : current.locations) {
result = dfs(visitedAlready,l,id);
if(result != null)
break;
}
return result;
}
这是一个粗略的轮廓。如果你在Java chat与我联系,我会给予更多的投入,最终会有更多的光滑和可重复使用的东西。我没有声称上述DFS有效。但它很接近
答案 1 :(得分:1)
我不确定我是否完全理解,但在“退出”中做出了名字。数组成为子节点?不确定Exit对象上有哪些方法,或者这甚至是远程最有效的解决方案,而且不幸的是我现在无法检查语法。
这个想法是该方法接受一个节点,找到子节点,然后有效地递归地调用该节点上的方法“步行&#39;在层次结构中。
ArrarList<Location> allNodes
// Create children for the specified node
public void createChildNodes(node n){
// Fetch all available exits
for(Exit e : n.getExit()){
// Iterate through all possible nodes
for(tempNode : allNodes) {
// Check if the 'exit' node matches one of the available nodes
if(tempNode.getName().equals(e.getName()){
// Match found, add it
n.addChildNode(tempNode, tempNode.getDistance));
// Check for children nodes of the temp node
createChildNodes(tempNode);
}
}
}
}