use*_*198 6 javascript algorithm graph-theory graph-algorithm data-structures
我有一个对象列表(无向边),如下所示:
pairs = [
pair:["a2", "a5"],
pair:["a3", "a6"],
pair:["a4", "a5"],
pair:["a7", "a9"]
];
Run Code Online (Sandbox Code Playgroud)
我需要在不同的组中找到所有组件(连接的节点).所以从给定的对中我需要得到:
groups = [
group1: ["a2", "a5", "a4"],
group2: ["a3", "a6"],
group3: ["a7", "a9"]
];
Run Code Online (Sandbox Code Playgroud)
我实际上在这里阅读了一些答案并用Google搜索,这就是我学习它的方法,称为"在图中查找连接的组件",但是找不到任何示例代码.我在Node.js上使用JavaScript,但任何其他语言的样本都会非常有用.谢谢.
yan*_*han 11
这可以使用广度优先搜索来解决.
我们的想法是通过跳转到相邻的顶点来遍历源顶点的所有可到达顶点.首先访问源顶点旁边的顶点,然后是2跳的顶点,等等.
由于使用了图表表示,这里的代码效率不高,这是一个边缘列表.要获得更好的性能,您可能需要使用邻接列表.
这是JavaScript中的一些工作代码.我曾经node.js这样做:
// Breadth First Search function
// v is the source vertex
// all_pairs is the input array, which contains length 2 arrays
// visited is a dictionary for keeping track of whether a node is visited
var bfs = function(v, all_pairs, visited) {
var q = [];
var current_group = [];
var i, nextVertex, pair;
var length_all_pairs = all_pairs.length;
q.push(v);
while (q.length > 0) {
v = q.shift();
if (!visited[v]) {
visited[v] = true;
current_group.push(v);
// go through the input array to find vertices that are
// directly adjacent to the current vertex, and put them
// onto the queue
for (i = 0; i < length_all_pairs; i += 1) {
pair = all_pairs[i];
if (pair[0] === v && !visited[pair[1]]) {
q.push(pair[1]);
} else if (pair[1] === v && !visited[pair[0]]) {
q.push(pair[0]);
}
}
}
}
// return everything in the current "group"
return current_group;
};
var pairs = [
["a2", "a5"],
["a3", "a6"],
["a4", "a5"],
["a7", "a9"]
];
var groups = [];
var i, k, length, u, v, src, current_pair;
var visited = {};
// main loop - find any unvisited vertex from the input array and
// treat it as the source, then perform a breadth first search from
// it. All vertices visited from this search belong to the same group
for (i = 0, length = pairs.length; i < length; i += 1) {
current_pair = pairs[i];
u = current_pair[0];
v = current_pair[1];
src = null;
if (!visited[u]) {
src = u;
} else if (!visited[v]) {
src = v;
}
if (src) {
// there is an unvisited vertex in this pair.
// perform a breadth first search, and push the resulting
// group onto the list of all groups
groups.push(bfs(src, pairs, visited));
}
}
// show groups
console.log(groups);
Run Code Online (Sandbox Code Playgroud)
更新:我已更新我的答案,演示如何将边缘列表转换为邻接列表.代码被评论,应该很好地说明这个概念.修改宽度优先搜索功能以使用邻接列表,以及另一个略微修改(关于将顶点标记为已访问).
// Converts an edgelist to an adjacency list representation
// In this program, we use a dictionary as an adjacency list,
// where each key is a vertex, and each value is a list of all
// vertices adjacent to that vertex
var convert_edgelist_to_adjlist = function(edgelist) {
var adjlist = {};
var i, len, pair, u, v;
for (i = 0, len = edgelist.length; i < len; i += 1) {
pair = edgelist[i];
u = pair[0];
v = pair[1];
if (adjlist[u]) {
// append vertex v to edgelist of vertex u
adjlist[u].push(v);
} else {
// vertex u is not in adjlist, create new adjacency list for it
adjlist[u] = [v];
}
if (adjlist[v]) {
adjlist[v].push(u);
} else {
adjlist[v] = [u];
}
}
return adjlist;
};
// Breadth First Search using adjacency list
var bfs = function(v, adjlist, visited) {
var q = [];
var current_group = [];
var i, len, adjV, nextVertex;
q.push(v);
visited[v] = true;
while (q.length > 0) {
v = q.shift();
current_group.push(v);
// Go through adjacency list of vertex v, and push any unvisited
// vertex onto the queue.
// This is more efficient than our earlier approach of going
// through an edge list.
adjV = adjlist[v];
for (i = 0, len = adjV.length; i < len; i += 1) {
nextVertex = adjV[i];
if (!visited[nextVertex]) {
q.push(nextVertex);
visited[nextVertex] = true;
}
}
}
return current_group;
};
var pairs = [
["a2", "a5"],
["a3", "a6"],
["a4", "a5"],
["a7", "a9"]
];
var groups = [];
var visited = {};
var v;
// this should look like:
// {
// "a2": ["a5"],
// "a3": ["a6"],
// "a4": ["a5"],
// "a5": ["a2", "a4"],
// "a6": ["a3"],
// "a7": ["a9"],
// "a9": ["a7"]
// }
var adjlist = convert_edgelist_to_adjlist(pairs);
for (v in adjlist) {
if (adjlist.hasOwnProperty(v) && !visited[v]) {
groups.push(bfs(v, adjlist, visited));
}
}
console.log(groups);
Run Code Online (Sandbox Code Playgroud)
使用Disjoint Set Forest算法最好地解决您要解决的任务.
基本上它意味着以最佳方式准确解决您描述的问题.
root(v).在整个算法中,每个这样的集合将被视为种植树.因此,我们将与root(v)树的根相关联.所以我们假设root(v)返回一个顶点索引.parent[v] = -1为每个算法启动算法,v因为所有顶点最初都在自己的树中,而您没有父项rank.我们将所有等级初始化为1这是一个伪代码:
parent[v] = -1 for v in Vertices
rank[v] = 1 for v in Vertices
root (v):
processed = []
while parent[v] != -1
processed << v
v = parent[v]
for vertex : processed
parent = v // optimisation: here we move the assoc. trees to be directly connected the root
return v
join (v1, v2):
if rank[v1] < rank[v2]:
parent[v1] = v2
if rank[v1] > rank[v2]:
parent[v2] = v1
parent[v2] = v1
rank[v1]++
merge_trees (v1, v2)
root1 = root(v1)
root2 = root(v2)
if root1 == root2:
// already in same tree nothing else to be done here
return true
else
// join trees
join (v1, v2)
return false
main:
numberTrees = size(Vertives)
for edge: edges
if merge_trees(edge.begin, edge.end):
numberTrees--
print numberTrees // this is the number you are interested in.
Run Code Online (Sandbox Code Playgroud)
注意如果你没有太多的表现,你可以省略等级的事情.没有它,你的算法可能会运行得更慢,但也许你更容易理解和维护.在这种情况下,您可以join在任何方向上进行顶点.我应警告您,然后会存在会触发您的算法运行速度较慢的场景.
| 归档时间: |
|
| 查看次数: |
9984 次 |
| 最近记录: |