我有一个Dictionary<int, List<int>>
,其中Key表示集合的元素(或面向图中的顶点),List是一组与Key相关的其他元素(所以有从键到值的定向边缘)。字典已针对创建Hasse图进行了优化,因此值始终小于Key。
我还有一个简单的顺序算法,删除所有传递边缘(例如,我有关系1-> 2,2-> 3和1-> 3.我可以删除边缘1-> 3,因为我有1到3之间的路径2)。
for(int i = 1; i < dictionary.Count; i++)
{
for(int j = 0; j < i; j++)
{
if(dictionary[i].Contains(j))
dictionary[i].RemoveAll(r => dictionary[j].Contains(r));
}
}
是否可以并行化算法?我可以做内部循环的Parallel.For。但是,建议不要这样做(https://msdn.microsoft.com/en-us/library/dd997392(v=vs.110).aspx#Anchor_2),结果速度不会显着增加(+可能存在锁定问题)。我可以并行化外循环吗?
答案 0 :(得分:0)
有一种简单的方法可以解决并行化问题,分离数据。从原始数据结构读取并写入新的。这样你就可以并行运行它,甚至不需要锁定。
但可能并行化并不是必需的,数据结构效率不高。你使用数组就足够了(因为我理解你有顶点0..result.Count-1
的代码)。 List<int>
用于查找。 List.Contains
非常低效。 HashSet
会更好。或者,对于更密集的图表,BitArray
。因此,而不是Dictionary<int, List<int>>
您可以使用BitArray[]
。
我重写了算法并进行了一些优化。它不会生成图形的简单副本并删除边缘,它只是从右边缘构造新图形。它使用BitArray[]
作为输入图,List<int>[]
作为最终图,因为后者更稀疏。
int sizeOfGraph = 1000;
//create vertices of a graph
BitArray[] inputGraph = new BitArray[sizeOfGraph];
for (int i = 0; i < inputGraph.Length; ++i)
{
inputGraph[i] = new BitArray(i);
}
//fill random edges
Random rand = new Random(10);
for (int i = 1; i < inputGraph.Length; ++i)
{
BitArray vertex_i = inputGraph[i];
for(int j = 0; j < vertex_i.Count; ++j)
{
if(rand.Next(0, 100) < 50) //50% fill ratio
{
vertex_i[j] = true;
}
}
}
//create transitive closure
for (int i = 0; i < sizeOfGraph; ++i)
{
BitArray vertex_i = inputGraph[i];
for (int j = 0; j < i; ++j)
{
if (vertex_i[j]) { continue; }
for (int r = j + 1; r < i; ++r)
{
if (vertex_i[r] && inputGraph[r][j])
{
vertex_i[j] = true;
break;
}
}
}
}
//create transitive reduction
List<int>[] reducedGraph = new List<int>[sizeOfGraph];
Parallel.ForEach(inputGraph, (vertex_i, state, ii) =>
{
{
int i = (int)ii;
List<int> reducedVertex = reducedGraph[i] = new List<int>();
for (int j = i - 1; j >= 0; --j)
{
if (vertex_i[j])
{
bool ok = true;
for (int x = 0; x < reducedVertex.Count; ++x)
{
if (inputGraph[reducedVertex[x]][j])
{
ok = false;
break;
}
}
if (ok)
{
reducedVertex.Add(j);
}
}
}
}
});
MessageBox.Show("Finished, reduced graph has "
+ reducedGraph.Sum(s => s.Count()) + " edges.");
修改强>
我写了这个:
代码有一些问题。随着方向结果证明是错误的。我这样想,让我们有一个图表i
现在,您可以删除您需要的边缘,结果将是不正确的。
1->0
2->1, 2->0
3->2, 3->1, 3->0
顶点2被顶点1缩小,所以我们有
1->0
2->1
3->2, 3->1, 3->0
现在顶点3被顶点2缩小
1->0
2->1
3->2, 3->0
我们遇到了一个问题,因为我们无法减少由于3->0
减少而留在这里的2->0
。但这是我的错,这绝不会发生。内循环严格地从低到高,所以改为
顶点3被顶点1缩小
1->0
2->1
3->2, 3->1
现在通过顶点2
1->0
2->1
3->2
结果是正确的。我为错误道歉。