누군가가 방향성 비순환 그래프가 무엇인지 간단한 용어로 설명 할 수 있습니까? 위키 백과를 살펴 봤지만 프로그래밍에서 그 용도를 실제로 볼 수는 없습니다.
누군가가 방향성 비순환 그래프가 무엇인지 간단한 용어로 설명 할 수 있습니까? 위키 백과를 살펴 봤지만 프로그래밍에서 그 용도를 실제로 볼 수는 없습니다.
답변:
그래프 = 가장자리로 서로 연결된 노드로 구성된 구조
Directed = 노드 (가장자리) 사이의 연결은 방향을 갖습니다. A-> B는 B-> A와 동일하지 않습니다.
acyclic = "non-circular"= 가장자리를 따라 노드에서 노드로 이동하면 두 번째로 동일한 노드를 만나지 않습니다.
방향성 비순환 그래프의 좋은 예는 트리입니다. 그러나 모든 유 방향 비순환 그래프가 트리는 아닙니다.
DAG (Directed Acyclic Graph)의 의미를 나타내는 많은 답변이 있지만 해당 응용 프로그램에 대한 답변은 없습니다. 여기 아주 간단한 것이 있습니다.
전제 조건 그래프 -엔지니어링 과정에서 모든 학생은 전제 조건과 같은 요구 사항을 따르는 과목을 선택하는 과제에 직면합니다. 이제 알고리즘 [A]에 대한 사전 필수 과정 없이는 인공 지능 [B]에 대한 수업을 수강 할 수 없습니다. 따라서 B는 A에 의존하거나 더 나은 용어로 A는 B로 향하는 우위를 가지고 있습니다. 따라서 노드 B에 도달하려면 노드 A를 방문해야합니다. 전제 조건이있는 모든 주제를 그래프에 추가하면 곧 분명해질 것입니다. , 그것은 방향성 비순환 그래프로 판명 될 것입니다.
주기가 있었다면 코스를 완료하지 못할 것입니다.
학생들이 과정에 등록 할 수 있도록하는 대학의 소프트웨어 시스템은 학생이 현재 과정에 등록하기 전에 필수 과정을 수강했는지 확인하기 위해 과목을 노드로 모델링 할 수 있습니다.
제 교수님이이 비유를 해주셨 고 복잡한 개념을 사용하는 것보다 DAG를 이해하는 데 가장 큰 도움이되었습니다!
또 다른 실시간 예-> 버전 시스템에서 DAG를 사용할 수있는 실시간 예
프로그래밍에서 방향성 비순환 그래프를 사용하는 예에는 연결성과 인과 관계를 나타내는 모든 것이 포함됩니다.
예를 들어 런타임에 구성 가능한 계산 파이프 라인이 있다고 가정합니다. 예를 들어 계산 A, B, C, D, E, F 및 G가 서로 의존한다고 가정합니다. A는 C에, C는 E와 F에, B는 D와 E에, D는 F. 이것은 DAG로 표현 될 수 있습니다. 메모리에 DAG가 있으면 다음과 같은 알고리즘을 작성할 수 있습니다.
다른 많은 것들 중에서.
응용 프로그램 프로그래밍 영역 밖에서 괜찮은 자동화 된 빌드 도구 (make, ant, scons 등)는 DAG를 사용하여 프로그램 구성 요소의 적절한 빌드 순서를 보장합니다.
몇 가지 답변이 그래프 사용 (예 : 네트워크 모델링)의 예를 제공했으며 "이것이 프로그래밍과 어떤 관련이 있습니까?"라고 물었습니다.
그 하위 질문에 대한 대답은 프로그래밍과 관련이별로 없다는 것입니다. 그것은 문제 해결과 관련이 있습니다.
연결 목록이 특정 문제 클래스에 사용되는 데이터 구조 인 것처럼 그래프는 특정 관계를 나타내는 데 유용합니다. 연결된 목록, 트리, 그래프 및 기타 추상 구조는 코드에서 구현할 수 있다는 점에서 프로그래밍과 만 연결됩니다. 그들은 더 높은 수준의 추상화에 존재합니다. 프로그래밍이 아니라 문제 해결에 데이터 구조를 적용하는 것입니다.
DAG (Directed Acyclic Graph)에는 다른 그래프와 구별되는 다음과 같은 속성이 있습니다.
글쎄요, 지금 당장 한 가지 용도를 생각할 수 있습니다. DAG ( Gate-For-Graphs 로 알려짐 -더 많은 기술적 세부 사항 )는 일련의 프로세스 및 리소스 (둘 다 DAG의 노드) 간의 종속성을 설명하므로 교착 상태를 감지하는 데 편리합니다. . 주기가 감지되면 교착 상태가 발생합니다.
기본 그래프 용어를 이미 알고 있다고 가정합니다. 그렇지 않으면 그래프 이론 에 대한 기사에서 시작해야합니다 .
Directed 는 모서리 (연결)에 방향이 있다는 사실을 나타냅니다. 다이어그램에서 이러한 방향은 화살표로 표시됩니다. 그 반대는 무 방향 그래프로, 간선이 방향을 지정하지 않습니다.
비순환 이란 임의의 노드 X에서 시작하여 가능한 모든 에지를 통과하는 경우 이미 사용 된 에지로 돌아 가지 않고는 X로 돌아갈 수 없음을 의미합니다.
여러 응용 프로그램 :
DAG는 모든 것이 같은 방향으로 흐르고 어떤 노드도 자신을 다시 참조 할 수없는 그래프입니다.
조상 나무를 생각하십시오. 실제로 DAG입니다.
모든 DAG에는
DAG는 나무와 다릅니다. 나무와 같은 구조에서는 두 노드마다 고유 한 경로가 있어야합니다. DAG에서 노드는 두 개의 상위 노드를 가질 수 있습니다.
다음 은 DAG에 대한 좋은 기사 입니다. 도움이 되었기를 바랍니다.
모든 종류의 그래프는 다양한 실제 관계를 모델링하기 위해 프로그래밍에 사용됩니다. 예를 들어 소셜 네트워크는 종종 그래프로 표시됩니다 (이 경우 순환). 마찬가지로, 네트워크 토폴로지, 패밀리 트리, 항공 노선, ...
소스 코드 또는 3 개의 주소 (TAC) 코드 관점에서이 페이지에서 문제를 정말 쉽게 시각화 할 수 있습니다.
http://cgm.cs.mcgill.ca/~hagha/topic30/topic30.html#Exptree
표현식 트리 섹션으로 이동 한 다음 페이지를 조금 아래로 내려 가면 트리의 "위상 정렬"과 표현식 평가 방법에 대한 알고리즘이 표시됩니다.
따라서이 경우 DAG를 사용하여 표현식을 평가할 수 있습니다. 이는 평가가 일반적으로 해석되고 이러한 DAG 평가자를 사용하면 기본적으로 스택에 푸시 및 팝핑하지 않고 제거하기 때문에 간단한 intrepreters를 더 빠르게 만들 수 있습니다. 일반적인 하위 표현.
고대 이집트 (즉, 영어)에서 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;
}
예를 들어 소스 코드의 표현식 트리와 같이 자신의 코드에서 트리를 살펴 보는 것입니다. 예를 들어 기존 노드 XNodes를 호출하십시오.
따라서 각 XNode에 대해 DAG에 추가하는 방법을 결정해야하며 이미 DAG에있을 가능성이 있습니다.
이것은 매우 간단한 의사 코드입니다. 컴파일 용이 아닙니다.
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입니다.
분명히 예제 절차는 더 작은 부분으로 나눌 수 있거나 가상 기능이있는 하위 클래스로 만들 수 있습니다.
Dag를 정렬하려면 각 DagNode를 왼쪽에서 오른쪽으로 이동합니다. 즉, DagNodes 왼쪽 가장자리를 따른 다음 오른쪽 가장자리를 따릅니다. 번호는 반대로 할당됩니다. 즉, 자식이없는 DagNode에 도달하면 해당 노드에 현재 정렬 번호를 할당하고 정렬 번호를 증가시켜 재귀가 해제되어 번호가 오름차순으로 할당되도록합니다.
이 예제는 자식이 0 개 또는 2 개인 노드가있는 트리 만 처리합니다. 분명히 일부 트리에는 둘 이상의 자식이있는 노드가 있으므로 논리는 여전히 동일합니다. 왼쪽과 오른쪽을 계산하는 대신 왼쪽에서 오른쪽으로 계산하십시오.
// 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;
}
프로그래밍에 어떤 트리가 있는지 알고 있다면 프로그래밍의 DAG는 비슷하지만 노드가 둘 이상의 부모를 가질 수 있습니다. 이것은 노드가 단일 부모보다 더 많은 노드 아래에 뭉치도록하고 싶지만주기가있는 일반 그래프의 매듭이 엉망인 문제가 없을 때 편리 할 수 있습니다. 여전히 DAG를 쉽게 탐색 할 수 있지만 루트로 돌아가는 방법은 여러 가지가 있습니다 (부모가 둘 이상일 수 있기 때문). 단일 DAG는 일반적으로 여러 루트를 가질 수 있지만 실제로는 트리처럼 하나의 루트 만 사용하는 것이 더 나을 수 있습니다. OOP에서 단일 상속과 다중 상속을 이해한다면 트리와 DAG를 알 수 있습니다. 나는 이미 여기 에 대답 했다 .
그 이름은 그 정의에 대해 알아야 할 대부분을 알려줍니다. 모든 가장자리가 한 방향으로 만 흐르는 그래프이며 가장자리를 기어 내려 가면 경로가 방금 떠난 정점으로 돌아 가지 않습니다.
모든 용도에 대해 말할 수는 없지만 (Wikipedia에서 도움이 됨), 저에게 DAG는 리소스 간의 종속성을 결정할 때 매우 유용합니다. 예를 들어 내 게임 엔진은로드 된 모든 리소스 (머티리얼, 텍스처, 셰이더, 일반 텍스트, 구문 분석 된 json 등)를 단일 DAG로 나타냅니다. 예:
재료는 N GL 프로그램으로, 각각 두 개의 셰이더가 필요하고 각 셰이더에는 일반 텍스트 셰이더 소스가 필요합니다. 이러한 리소스를 DAG로 나타내면 기존 리소스에 대한 그래프를 쉽게 쿼리하여 중복로드를 방지 할 수 있습니다. 여러 머티리얼이 동일한 소스 코드로 버텍스 쉐이더를 사용하기를 원한다고 가정 해 보겠습니다. 기존 리소스에 대한 새로운 에지를 설정할 수있을 때 모든 용도에 대해 소스를 다시로드하고 셰이더를 다시 컴파일하는 것은 낭비입니다. 이런 식으로 그래프를 사용하여 리소스에 의존하는 것이 있는지 확인하고 그렇지 않은 경우 삭제하고 메모리를 해제 할 수 있습니다. 실제로 이것은 거의 자동으로 발생합니다.
확장으로 DAG는 데이터 처리 파이프 라인을 표현하는 데 유용합니다. 비순환 적 특성은 동일한 정점을 다시 확인하지 않고도 정점에서 가장자리 아래로 포인터를 따라갈 수있는 상황 별 처리 코드를 안전하게 작성할 수 있음을 의미합니다. VVVV , Max MSP 또는 Autodesk Maya의 노드 기반 인터페이스 와 같은 시각적 프로그래밍 언어는 모두 DAG에 의존합니다.
방향성 비순환 그래프는 ... 방향성 비순환 그래프를 표현하고 싶을 때 유용합니다! 정식 예는 가계도 또는 계보입니다.