- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在 C# 项目中,我有一组要执行的测试。每个测试都有自己依赖的测试集合。测试网络需要形成有向无环图 (DAG)。
使用符号 A -> B -> C,其中 A、B、C 代表测试,然后
C依赖于B,B 依赖于 A。
我已经有一个算法可以对测试进行排序,这样我就可以按顺序处理它们,从而尊重所有依赖关系。也就是说,顺序意味着在为整个图评估测试本身之前先评估每个测试的依赖项。
我想要的是一种算法,它首先进行一组测试,然后可以将它们划分为单独的 DAG 图(如果存在)。每个 DAG 中的测试不需要排序,因为可以单独完成。这样做的原因是我可以将每个独立的 DAG 作为一个单独的任务运行,并通过这种方式获得一些效率。
因此,考虑一组测试 A、B、C、D、E、F,其依赖项是:
A -> B -> C
D -> C
E -> F
从算法中我想要 2 组测试,
Set 1) A,B,C,D
Set 2) E,F
更新:帮助向 Eric 请求的 C# 代码。
public class Graph
{
private List<Node> _nodes = new List<Node>();
public IReadOnlyList<Node> Nodes => _nodes;
public void AddNode(Node node)
{
_nodes.Add(node);
}
public void RemoveRange(IEnumerable<Node> nodes)
{
foreach (var item in nodes)
{
_nodes.Remove(item);
}
}
}
public class Node
{
public Node(string name)
{
Name = name;
}
private List<Node> _dependants = new List<Node>();
public string Name { get; private set; }
public IReadOnlyList<Node> Dependents => _dependants;
public void AddDependent(Node node)
{
_dependants.Add(node);
}
}
public class Set
{
private List<Node> _elements = new List<Node>();
public void AddRange(IEnumerable<Node> nodes)
{
_elements = new List<Node>(nodes);
}
public IReadOnlyList<Node> Elements => _elements;
}
internal class Program
{
private static void Main(string[] args)
{
List<Set> sets = new List<Set>();
var graph = new Graph();
var a = new Node("A");
var b = new Node("B");
var c = new Node("C");
var d = new Node("D");
var e = new Node("E");
var f = new Node("F");
graph.AddNode(a);
graph.AddNode(b);
graph.AddNode(c);
graph.AddNode(d);
graph.AddNode(e);
graph.AddNode(f);
c.AddDependent(b);
b.AddDependent(a);
c.AddDependent(d);
f.AddDependent(e);
while (graph.Nodes.Count > 0)
{
var set = new Set();
var pickNode = graph.Nodes[0];
// Get reachable nodes
// 1. NOT SURE WHAT YOU MEAN HERE AND HOW TO DO THIS IN C#
// 2. ALSO, DOES THE SET INCLUDE THE PICKED NODE?
}
}
}
更新 2:
排序节点的代码示例
private enum MarkType
{
None,
Permanent,
Temporary
}
private static IEnumerable<T> GetSortedNodes<T>(DirectedGraph<T> directedGraph)
{
List<T> L = new List<T>();
var allNodes = directedGraph.Nodes();
Dictionary<T, (MarkType, T)> nodePairDictionary = allNodes.ToDictionary(n => n, n => (MarkType.None, n));
foreach (var node in allNodes)
{
var nodePair = nodePairDictionary[node];
Visit(nodePair);
}
return L.Reverse<T>().ToList();
void Visit((MarkType markType, T node) nodePair)
{
if (nodePair.markType == MarkType.Permanent)
{
return;
}
if (nodePair.markType == MarkType.Temporary)
{
throw new Exception("NOT A DAG");
}
nodePair.markType = MarkType.Temporary;
foreach (var dependentNode in directedGraph.Edges(nodePair.node))
{
var depNodePair = nodePairDictionary[dependentNode];
Visit(depNodePair);
}
nodePair.markType = MarkType.Permanent;
L.Insert(0, nodePair.node);
}
}
最佳答案
pniederh 的答案给出了联合查找算法的一个(有点过于复杂的)版本;正如我在评论中指出的那样,有很多关于如何使这些算法高效的研究。
在您的特定情况下,另一种有效的算法是:
完成后,您将得到一个集合列表,其中每个集合都包含彼此具有某种直接或间接依赖关系的任务,并且每个任务都恰好出现在一个集合中。这是由对称依赖等价关系引入的一组等价类。
更新:还有一些关于如何实现这一点的其他问题。
这是一个简单但不是特别有效的实现。这里的想法是从更简单的数据结构构建越来越复杂的数据结构。
我首先要的是多词典。普通字典从键映射到值。我想要一个从键到一组值的映射。我们可以通过 NuGet 下载任意数量的实现,但编写我们自己的基本实现是快速且容易的:
public class MultiDictionary<K, V>
{
private readonly Dictionary<K, HashSet<V>> d = new Dictionary<K, HashSet<V>>();
public void Add(K k, V v)
{
if (!d.ContainsKey(k)) d.Add(k, new HashSet<V>());
d[k].Add(v);
}
public void Remove(K k, V v)
{
if (d.ContainsKey(k))
{
d[k].Remove(v);
if (d[k].Count == 0) d.Remove(k);
}
}
public void Remove(K k) => d.Remove(k);
public IEnumerable<V> GetValues(K k) => d.ContainsKey(k) ? d[k] : Enumerable.Empty<V>();
public IEnumerable<K> GetKeys() => d.Keys;
}
我希望你同意这是一个简单的抽象数据类型。
一旦我们有了多字典,我们就非常接近于有向图了。但是,我们不能将这个多字典用作有向图,因为它不代表没有出边的图节点的概念。因此,让我们构建一个使用多字典的简单有向图类型:
public class DirectedGraph<T>
{
private readonly HashSet<T> nodes = new HashSet<T>();
private readonly MultiDictionary<T, T> edges = new MultiDictionary<T, T>();
public void AddNode(T node) => nodes.Add(node);
public void AddEdge(T n1, T n2)
{
AddNode(n1);
AddNode(n2);
edges.Add(n1, n2);
}
public void RemoveEdge(T n1, T n2) => edges.Remove(n1, n2);
public void RemoveNode(T n)
{
// TODO: This algorithm is very inefficient if the graph is
// TODO: large; can you think of ways to improve it?
// Remove the incoming edges
foreach (T n1 in nodes)
RemoveEdge(n1, n);
// Remove the outgoing edges
foreach (T n2 in edges.GetValues(n).ToList())
RemoveEdge(n, n2);
// The node is now isolated; remove it.
nodes.Remove(n);
}
public IEnumerable<T> Edges(T n) => edges.GetValues(n);
public IEnumerable<T> Nodes() => nodes.Select(x => x);
public HashSet<T> ReachableNodes(T n) { ??? }
// We'll come back to this one!
}
这里有一些微妙之处;你明白我为什么使用 ToList
和 Select
了吗?
好的,我们现在有一个有向图来表示我们的依赖图。我们的算法需要一个无向图。但制作无向图最简单的方法是制作有向图,只需成对添加和删除边!
public class UndirectedGraph<T>
{
private readonly DirectedGraph<T> g = new DirectedGraph<T>();
public void AddNode(T node) => g.AddNode(node);
public void AddEdge(T n1, T n2)
{
g.AddEdge(n1, n2);
g.AddEdge(n2, n1);
}
public void RemoveEdge(T n1, T n2)
{
g.RemoveEdge(n1, n2);
g.RemoveEdge(n2, n1);
}
public void RemoveNode(T n) => g.RemoveNode(n);
public IEnumerable<T> Edges(T n) => g.Edges(n);
public IEnumerable<T> Nodes() => g.Nodes();
}
super 棒。为了使转换更容易,让我们向有向图添加一个辅助方法:
public UndirectedGraph<T> ToUndirected()
{
var u = new UndirectedGraph<T>();
foreach (T n1 in nodes)
{
u.AddNode(n1);
foreach (T n2 in Edges(n1))
u.AddEdge(n1, n2);
}
return u;
}
现在,我们算法的关键是能够获得给定节点的可达节点集。我希望你同意到目前为止一切都很简单。这是棘手的一点:
public HashSet<T> ReachableNodes(T n)
{
var reachable = new HashSet<T>();
if (nodes.Contains(n))
{
var stack = new Stack<T>();
stack.Push(n);
while (stack.Count > 0)
{
var current = stack.Pop();
if (!reachable.Contains(current))
{
reachable.Add(current);
foreach (T n2 in Edges(current))
stack.Push(n2);
}
}
}
return reachable;
}
这是有向图的深度优先遍历,它检测循环并返回给定节点的传递闭包。 仔细研究这个算法,因为它是理解的关键。
我们将向我们的无向图中添加一个辅助方法:
public HashSet<T> ReachableNodes(T n) => g.ReachableNodes(n);
现在我们拥有了制作算法所需的所有部分。我们只是将我给出的算法描述直接翻译成代码:
static IEnumerable<HashSet<T>> GetEquivalenceClasses<T>(DirectedGraph<T> d)
{
var u = d.ToUndirected();
var results = new List<HashSet<T>>();
while (u.Nodes().Any())
{
T current = u.Nodes().First();
HashSet<T> reachable = u.ReachableNodes(current);
results.Add(reachable);
foreach (T n in reachable)
u.RemoveNode(n);
}
return results;
}
让我们试一试:
var d = new DirectedGraph<string>();
d.AddEdge("A", "B");
d.AddEdge("B", "C");
d.AddEdge("D", "C");
d.AddEdge("E", "F");
foreach (var eq in GetEquivalenceClasses(d))
Console.WriteLine(string.Join(",", eq));
果然:
A,B,C,D
E,F
有道理吗?
更新:移除节点是代价高昂的部分,我刚刚意识到,我们不需要这样做。该算法的非破坏性版本是:
static IEnumerable<HashSet<T>> GetEquivalenceClasses<T>(DirectedGraph<T> d)
{
var u = d.ToUndirected();
var results = new List<HashSet<T>>();
var done = new HashSet<T>();
foreach(T current in u.Nodes())
{
if (done.Contains(current))
continue;
HashSet<T> reachable = u.ReachableNodes(current);
results.Add(reachable);
foreach(T n in reachable)
done.Add(n);
}
return results;
}
关于c# - 如何将一组节点划分为子集,每个子集形成有向无环图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52850826/
我正在执行大型 ffdf 对象的子集,我注意到当我使用 subset.ff 时,它会生成大量 NA。我通过使用 ffwhich 尝试了另一种方法,结果要快得多,并且没有生成 NA。这是我的测试: li
我对 Prolog 有点陌生。我正在尝试编写一个函数subset(Set, Subset) 来确定Subset 是否是Set 的子集(duh)。另外,如果第二个参数没有实例化,它应该输出每个可能的子集
一、题目 给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 二、示例 输入:nums = [1,2
我想从数据帧的操作中排除一列。当然,我可以在没有要排除的列的情况下复制数据框,但这似乎是一种解决方法。我认为必须有一种更简单的方法来进行子集化。 所以这个示例代码应该显示我在做什么。 df colMe
我有一个 SpatialPolygonsDataFrame我通过使用 readOGR 读取 shapefile 创建的在 rgdal包裹。我正在尝试使用它来使用 spsample 生成采样网格在 sp
我想解决一个简单的问题,但即使我尝试了很多不同的方法,我也找不到解决方案。我正在使用 SICStus Prolog (如果这很重要),并且我想获取列表的所有子列表/子集(我不知道哪个术语是正确的),其
我目前正在使用 shinyTable,它是 HandsonTable (https://github.com/trestletech/shinyTable) 的 shiny 兼容实现。巧合的是,我意识
我正在 Delphi 中构建一个表单,其中包含服务下拉列表和用于选择服务的附加组件网格。我获取的数据来自 API,并且我将服务的数据存储在 ADODataSet 中,如下所示: ID (integer
subset() 函数有问题。如何通过观察次数对我的数据框的一个因子进行子集化? NAME CLASS COLOR VALUE antonio
我想知道是否有任何简单的算法来比较一个散列是否是另一个散列的子集。 例如,如果 $HASH{A} = B; $HASH{B} = C; $HASH{C} = D; $HASH2{A} = B; $HA
这个问题在这里已经有了答案: Array combinations without repetition (1 个回答) 关闭 8 年前。 给定一个数组,如何在 postgresql 中找到一定大小
我有下一个程序。我应该如何在 main 中使用迭代器以显示总和为 0 的子集? 我的程序应该打印: 2 -2 5 -5 # include # include using namespace st
我正在寻找一个可以自定义的 Markdown 解析器,最好是 Javascript。特别是,我想删除使用实际 HTML 标签的选项。我尝试编辑摊牌的来源,但无法弄清楚。 Jquery 集成也很好,尽管
我有一个包含名称列表的文件(引用文件 1): Apple Bat Cat 我有另一个文件(引用文件 2),其中包含名称列表和详细信息引用: Apple bla blaa aaaaaaaaagggggg
我有两个带有排序行的文件。一个文件 (B) 是另一个文件 (A) 的子集。我想找到 A 中不在 B 中的所有行。理想情况下,我想创建一个包含这些行的文件 (C)。这在 Unix 中可能吗?我正在寻找一
我有一个包含肽序列的列的数据框,我只想保留字符串中没有内部“R”或“K”的行。 df1 <- data.frame( Peptide = c("ABCOIIJUHFSAUJHR", "AOFI
这个问题在这里已经有了答案: How to subset matrix to one column, maintain matrix data type, maintain row/column na
假设我有一个列表向量: library(tidyverse) d 2) # A tibble: 5 x 1 x 1 2 3 4 5 最佳答案 应该是 lengt
我自己从来没有运行过javadoc(无论是在命令行还是ant's javadoc task;我将使用ant)——我需要为我编写的库生成一个javadoc。 问题是我的 java 库被组织成几个包,在
假设一个多方加密方案,类似于答案:Encryption with multiple different keys? . 那是。一组键K可以用来破译密文。 有没有办法过期: K'⊆ K 这样 K \ K
我是一名优秀的程序员,十分优秀!