Well, I can think of one use right now - DAG (known as 等待图表 - more 技术细节) are handy in detecting deadlocks as they illustrate the dependencies amongst a set of processes and resources (both are nodes in the DAG). Deadlock would happen when a cycle is detected.
所以在这种情况下,你可以使用 DAG 来计算表达式,这很方便,因为计算是正常解释的,使用这样的 DAG 计算器将使简单的解释器在主体上更快,因为它不会推送和弹出到堆栈,也因为它消除了常见的子表达式。
用非古埃及语(即英语)计算 DAG 的基本算法如下:
1)让你的 DAG 对象像这样
您需要一个活动列表,该列表包含所有当前活动 DAG 节点和 DAG 子表达式。DAG 子表达式是 DAG 节点,或者也可以称之为内部节点。我所说的活动 DAG 节点是指,如果你赋值给一个变量 X,那么它就变成活动的。然后使用 X 的公共子表达式使用该实例。如果再次分配 X,那么创建一个 NEW DAG NODE 并将其添加到活动列表中,旧的 X 将被删除,因此使用 X 的下一个子表达式将引用新实例,因此不会与仅使用相同变量名的子表达式发生冲突。
一旦你赋值给一个变量 X,那么在赋值点活动的所有 DAG 子表达式节点都会变成非活动的,因为新的赋值使得使用旧值的子表达式的意义无效。
class Dag {
TList LiveList;
DagNode Root;
}
// In your DagNode you need a way to refer to the original things that
// the DAG is computed from. In this case I just assume an integer index
// into the list of variables and also an integer index for the opertor for
// Nodes that refer to operators. Obviously you can create sub-classes for
// different kinds of Dag Nodes.
class DagNode {
int Variable;
int Operator;// You can also use a class
DagNode Left;
DagNode Right;
DagNodeList Parents;
}
因此,对于每个 XNode,您需要决定如何将其添加到 DAG 中,而且有可能它已经在 DAG 中了。
This is very simple pseudo code. Not intended for compilation.
DagNode XNode::GetDagNode(Dag dag) {
if (XNode.IsAssignment) {
// The assignment is a special case. A common sub expression is not
// formed by the assignment since it creates a new value.
// Evaluate the right hand side like normal
XNode.RightXNode.GetDagNode();
// And now take the variable being assigned to out of the current live list
dag.RemoveDagNodeForVariable(XNode.VariableBeingAssigned);
// Also remove all DAG sub expressions using the variable - since the new value
// makes them redundant
dag.RemoveDagExpressionsUsingVariable(XNode.VariableBeingAssigned);
// Then make a new variable in the live list in the dag, so that references to
// the variable later on will see the new dag node instead.
dag.AddDagNodeForVariable(XNode.VariableBeingAssigned);
}
else if (XNode.IsVariable) {
// A variable node has no child nodes, so you can just proces it directly
DagNode n = dag.GetDagNodeForVariable(XNode.Variable));
if (n) XNode.DagNode = n;
else {
XNode.DagNode = dag.CreateDagNodeForVariable(XNode.Variable);
}
return XNode.DagNode;
}
else if (XNode.IsOperator) {
DagNode leftDagNode = XNode.LeftXNode.GetDagNode(dag);
DagNode rightDagNode = XNode.RightXNode.GetDagNode(dag);
// Here you can observe how supplying the operator id and both operands that it
// looks in the Dags live list to check if this expression is already there. If
// it is then it returns it and that is how a common sub-expression is formed.
// This is called an internal node.
XNode.DagNode =
dag.GetOrCreateDagNodeForOperator(XNode.Operator,leftDagNode,RightDagNode) );
return XNode.DagNode;
}
}
这是一种看待问题的方式。树的基本遍历,只是添加和引用 Dag 节点。例如,dag 的根就是树的根返回的 DagNode。
// Most basic DAG topological ordering example.
void DagNode::OrderDAG(int* counter) {
if (this->AlreadyCounted) return;
// Count from left to right
for x = 0 to this->Children.Count-1
this->Children[x].OrderDag(counter)
// And finally number the DAG Node here after all
// the children have been numbered
this->DAGOrder = *counter;
// Increment the counter so the caller gets a higher number
*counter = *counter + 1;
// Mark as processed so will count again
this->AlreadyCounted = TRUE;
}
先决条件图 -在工程课程中,每个学生都要面对一项任务,即选择符合先决条件等要求的科目。现在很明显,你不能在没有必要的算法课程的情况下选修人工智能课程。因此 B 依赖于 A,或者用更好的术语 A 有一个指向 B 的边。因此,为了到达节点 B,您必须访问节点 A。很快我们就会明白,在把所有具备必要条件的科目加入到一个图表中之后,它将变成一个有向无环图。