边是指顶点,顶点是指边。我认为这是很自然的。
这是一个有缺陷的假设。顶点指向它们的边并且边也指向它们的顶点是不自然的。一个应该引用另一个,而不是它们都相互引用。具有重复的参考责任可能会导致各种问题。例如,如果它们不同步,您将没有真实的来源来重建您的图表。
为了避免循环依赖,您需要有一个关系的“所有者”。在您的特定示例中,引用顶点的边让我觉得是更明显的“所有者”,如下所示:
// vertex.js
goog.provide('Vertex');
goog.require('goog.math.Coordinate');
/**
* @constructor
* @param {number=} opt_x x-position, defaults to 0
* @param {number=} opt_y y-position, defaults to 0
* @extends {goog.math.Coordinate}
*/
Vertex = function(opt_x, opt_y) {
goog.base(this, opt_x, opt_y);
};
那么你的优势...
// edge.js
goog.provide('Edge');
goog.require('Vertex');
goog.require('goog.math.Coordinate');
/**
* @constructor
* @param {Vertex} start
* @param {Vertex} end
*/
Edge = function(start, end) {
/**
* @type {Vertex}
* @private
*/
this.start_ = start;
/**
* @type {Vertex}
* @private
*/
this.end_ = end;
};
/**
* @return {number}
*/
Edge.prototype.getDistance = function() {
goog.math.Coordinate.distance(this.start_, this.end_);
};
/**
* Checks if this Edge connects to the referenced vertex.
* @param {Vertex} vertex
* @return {bool}
*/
Edge.prototype.connects = function(vertex) {
return this.start_ === vertex || this.end_ === vertex;
};
/**
* @return {Vertex}
*/
Edge.prototype.getStart = function() {
return this.start_;
};
/**
* @return {Vertex}
*/
Edge.prototype.getEnd = function() {
return this.end_;
};
然后你的图表...
/**
* @param {Array.<Edge>} edges
* @constructor
*/
Graph = function(edges) {
/**
* @type {Array.<Edge>}
* @private
*/
this.edges_ = edges;
};
/**
* @param {Vertex} start
* @param {Vertex} end
* @return {number|undefined} shortest path between {@code start} and {@code end},
* with 'undefined' being returned if a path does not exist.
*/
Graph.prototype.getShortestPath = function(start, end) {
return this.getShortestPath_(start, end, 0, []);
}
/**
* @param {Vertex} start
* @param {Vertex} end
* @param {number} traveled amount traveled thus far
* @param {Array.<Vertex>} path the route taken thus far
* @return {number|undefined}
* @private
*/
Graph.prototype.getShortestPath_ = function(start, end, traveled, path) {
if (start == end) {
return traveled + 0;
}
var distances = goog.array.map(
this.getEdgesToTry_(start, path),
function (edge) {
var nextStart;
if (edge.getStart() === start) {
nextStart = edge.getEnd();
} else {
nextStart = edge.getStart();
}
return this.getShortestPath_(
newStart,
end,
edge.getDistance() + traveled,
goog.array.concat(path, start)
);
},
this
);
return goog.array.reduce(
distances,
function (shortestDistance, distance) {
if (distance !== undefined) {
if (shortestDistance === undefined) {
return distance;
} else {
return Math.min(shortestDistance, distance);
}
} else {
return shortestDistance;
}
},
undefined
);
};
/**
* @param {Vertex} vertex
* @param {Array.<Vertex>} path
* @return {Array.<Vertex>}
* @private
*/
Graph.prototype.getEdgesToTry_ = function(vertex, path) {
return goog.array.filter(
this.edges_,
function (edge) { return this.isEdgeToTry_(edge, vertex, path); },
this
);
};
/**
* @param {Edge} edge
* @param {Vertex} start
* @param {Array.<Vertex>} path
* @return {bool}
* @private
*/
Graph.prototype.isEdgeToTry_ = function(edge, start, path) {
return edge.connects(start)
&& goog.array.every(
path, function(vertex) { return !edge.connects(vertex); });
};
警告:我没有对此进行测试——这是我在一瓶不错的波多黎各朗姆酒上捣碎的。我可能(阅读:可能)在这里或那里有一些事情搞砸了。无论如何,这个概念是成立的。这表明,对于给定的语言或技术,为了回答有关图的问题,循环依赖不是必要的(老实说,也不是可取的)要求。