Существует простой способ решить проблему параллелизации, отдельные данные. Прочтите исходную структуру данных и напишите на новую. Таким образом, вы можете запускать его параллельно, даже не требуя блокировки.
Но, вероятно, распараллеливание даже не требуется, структуры данных неэффективны. Вы используете словарь, где будет достаточно массива (поскольку я понимаю код У вас есть вершины 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.");
EDIT
я написал: код имеет некоторые проблемы. С направлением i
теперь можно удалить края, которые вам нужны, и результат будет неправильным. Это оказалось ошибкой. Я думал, таким образом, позволяет иметь график
1->0
2->1, 2->0
3->2, 3->1, 3->0
Vertex 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
. Но это моя ошибка, этого никогда не произойдет.Внутренний цикл проходит строго от низшего к высшему, так что вместо
Vertex 3 получает уменьшается на вершине 1
1->0
2->1
3->2, 3->1
и теперь от вершины 2
1->0
2->1
3->2
И результат является правильным. Прошу прощения за ошибку.
Search Stackoverflow for "thread safe dictionary" – jdweng
Является ли график транзитивным закрытием? В противном случае это не сработало бы (подумайте о 1-> 2, 2-> 3, 3-> 4, 1-> 4). –
Да, это так. Если бы это не так, диаграмма Хассе не могла быть сформирована. – Storm