ใครช่วยอธิบายให้ฉันเข้าใจง่ายๆว่ากราฟอะไซคลิกคืออะไร ฉันได้ดู Wikipedia แล้ว แต่มันไม่ได้ทำให้ฉันเห็นว่ามันใช้ในการเขียนโปรแกรมได้จริงๆ
ใครช่วยอธิบายให้ฉันเข้าใจง่ายๆว่ากราฟอะไซคลิกคืออะไร ฉันได้ดู Wikipedia แล้ว แต่มันไม่ได้ทำให้ฉันเห็นว่ามันใช้ในการเขียนโปรแกรมได้จริงๆ
คำตอบ:
กราฟ = โครงสร้างประกอบด้วยโหนดที่เชื่อมต่อกันด้วยขอบ
กำกับ = การเชื่อมต่อระหว่างโหนด (ขอบ) มีทิศทาง: A -> B ไม่เหมือนกับ B -> A
acyclic = "non-circular" = ย้ายจากโหนดไปยังโหนดโดยไปตามขอบคุณจะไม่พบโหนดเดียวกันอีกเป็นครั้งที่สอง
ตัวอย่างที่ดีของกราฟ acyclic ที่กำหนดทิศทางคือต้นไม้ อย่างไรก็ตามโปรดทราบว่ากราฟ acyclic ที่กำหนดทิศทางทั้งหมดไม่ใช่ต้นไม้
ฉันเห็นคำตอบมากมายที่ระบุความหมายของ DAG (Directed Acyclic Graph) แต่ไม่มีคำตอบเกี่ยวกับการใช้งาน นี่คือสิ่งที่ง่ายมาก -
กราฟวิชาบังคับก่อน - ในระหว่างหลักสูตรวิศวกรรมนักเรียนทุกคนต้องเผชิญกับภารกิจในการเลือกวิชาที่เป็นไปตามข้อกำหนดเช่นข้อกำหนดเบื้องต้น ตอนนี้เป็นที่ชัดเจนว่าคุณไม่สามารถเรียนวิชาปัญญาประดิษฐ์ [B] ได้หากไม่มีหลักสูตรที่จำเป็นเบื้องต้นเกี่ยวกับอัลกอริทึม [A] ดังนั้น B จึงขึ้นอยู่กับ A หรือในแง่ที่ดีกว่า A จึงมีขอบนำไปสู่ B ดังนั้นเพื่อที่จะไปถึงโหนด B คุณต้องไปที่โหนด A ในไม่ช้ามันจะชัดเจนว่าหลังจากเพิ่มเรื่องทั้งหมดที่มีข้อกำหนดเบื้องต้นลงในกราฟแล้ว มันจะกลายเป็น Directed Acyclic Graph
ถ้ามีรอบแล้วคุณจะไม่จบหลักสูตร: p
ระบบซอฟต์แวร์ในมหาวิทยาลัยที่อนุญาตให้นักศึกษาลงทะเบียนหลักสูตรสามารถจำลองวิชาเป็นโหนดเพื่อให้แน่ใจว่านักเรียนได้เรียนหลักสูตรที่จำเป็นก่อนลงทะเบียนสำหรับหลักสูตรปัจจุบัน
อาจารย์ของฉันให้การเปรียบเทียบนี้และช่วยให้ฉันเข้าใจ DAG ได้ดีที่สุดแทนที่จะใช้แนวคิดที่ซับซ้อน!
อีกตัวอย่างเรียลไทม์ -> ตัวอย่างเรียลไทม์ของการใช้ DAG ในระบบเวอร์ชัน
ตัวอย่างการใช้กราฟ acyclic ที่กำหนดทิศทางในการเขียนโปรแกรมรวมถึงสิ่งต่างๆที่แสดงถึงการเชื่อมต่อและสาเหตุ
ตัวอย่างเช่นสมมติว่าคุณมีไปป์ไลน์การคำนวณที่กำหนดค่าได้ที่รันไทม์ จากตัวอย่างนี้สมมติว่าการคำนวณ A, B, C, D, E, F และ G ขึ้นอยู่กับซึ่งกันและกัน: A ขึ้นอยู่กับ C, C ขึ้นอยู่กับ E และ F, B ขึ้นอยู่กับ D และ E และ D ขึ้นอยู่กับ F. สิ่งนี้สามารถแสดงเป็น DAG เมื่อคุณมี DAG ในหน่วยความจำคุณสามารถเขียนอัลกอริทึมเพื่อ:
เหนือสิ่งอื่นใด
นอกขอบเขตของการเขียนโปรแกรมแอปพลิเคชันเครื่องมือสร้างอัตโนมัติที่เหมาะสม (make, ant, scons และอื่น ๆ ) จะใช้ DAG เพื่อให้แน่ใจว่าลำดับการสร้างส่วนประกอบของโปรแกรมที่เหมาะสม
คำตอบหลายคำได้ยกตัวอย่างการใช้กราฟ (เช่นการสร้างแบบจำลองเครือข่าย) และคุณถามว่า "สิ่งนี้เกี่ยวข้องกับการเขียนโปรแกรมอย่างไร"
คำตอบสำหรับคำถามย่อยนั้นก็คือไม่มีอะไรเกี่ยวข้องกับการเขียนโปรแกรมมากนัก มันเกี่ยวข้องกับการแก้ปัญหา
เช่นเดียวกับรายการที่เชื่อมโยงเป็นโครงสร้างข้อมูลที่ใช้สำหรับปัญหาบางประเภทกราฟมีประโยชน์ในการแสดงความสัมพันธ์บางอย่าง รายการที่เชื่อมโยงต้นไม้กราฟและโครงสร้างนามธรรมอื่น ๆ มีเพียงการเชื่อมต่อกับการเขียนโปรแกรมซึ่งคุณสามารถนำไปใช้ในโค้ดได้ มีอยู่ในระดับที่สูงขึ้นของนามธรรม ไม่เกี่ยวกับการเขียนโปรแกรม แต่เป็นการใช้โครงสร้างข้อมูลในการแก้ปัญหา
Directed Acyclic Graphs (DAG) มีคุณสมบัติดังต่อไปนี้ซึ่งแตกต่างจากกราฟอื่น ๆ :
ตอนนี้ฉันสามารถนึกถึงการใช้งานครั้งเดียว - DAG (เรียกว่าWait-For-Graphs - รายละเอียดทางเทคนิคเพิ่มเติม ) มีประโยชน์ในการตรวจจับการหยุดชะงักเนื่องจากแสดงให้เห็นถึงการพึ่งพาระหว่างชุดของกระบวนการและทรัพยากร (ทั้งสองเป็นโหนดใน DAG) . การหยุดชะงักจะเกิดขึ้นเมื่อตรวจพบวงจร
ฉันถือว่าคุณรู้คำศัพท์พื้นฐานเกี่ยวกับกราฟแล้ว มิฉะนั้นคุณควรเริ่มต้นจากบทความเกี่ยวกับทฤษฎีกราฟ
กำกับหมายถึงความจริงที่ว่าขอบ (การเชื่อมต่อ) มีทิศทาง ในแผนภาพทิศทางเหล่านี้จะแสดงโดยลูกศร ตรงกันข้ามคือกราฟที่ไม่มีทิศทางซึ่งขอบจะไม่ระบุทิศทาง
Acyclicหมายความว่าหากคุณเริ่มต้นจากโหนด X ใด ๆ โดยพลการใด ๆ และเดินผ่านขอบที่เป็นไปได้ทั้งหมดคุณจะไม่สามารถกลับไปที่ X ได้โดยไม่ต้องกลับไปที่ขอบที่ใช้ไปแล้ว
หลายแอปพลิเคชัน:
DAG คือกราฟที่ทุกอย่างไหลไปในทิศทางเดียวกันและไม่มีโหนดใดสามารถอ้างอิงกลับมาที่ตัวมันเองได้
นึกถึงต้นไม้บรรพบุรุษ; จริงๆแล้วพวกมันคือ DAG
DAG ทั้งหมดมี
DAG แตกต่างจากต้นไม้ ในโครงสร้างที่เหมือนต้นไม้ต้องมีเส้นทางที่ไม่ซ้ำกันระหว่างทุก ๆ สองโหนด ใน DAGs โหนดสามารถมีโหนดแม่ได้สองโหนด
นี่เป็นบทความที่ดีเกี่ยวกับ DABs ความ ฉันหวังว่าจะช่วยได้
กราฟทุกประเภทใช้ในการเขียนโปรแกรมเพื่อสร้างแบบจำลองความสัมพันธ์ในโลกแห่งความจริงที่แตกต่างกัน ตัวอย่างเช่นเครือข่ายสังคมมักแสดงด้วยกราฟ (ในกรณีนี้เป็นวงจร) ในทำนองเดียวกันโครงสร้างเครือข่ายต้นไม้ครอบครัวเส้นทางสายการบิน ...
จากซอร์สโค้ดหรือแม้กระทั่งสามมุมมองของโค้ดแอดเดรส (TAC) คุณสามารถเห็นภาพปัญหาได้อย่างง่ายดายที่หน้านี้ ...
http://cgm.cs.mcgill.ca/~hagha/topic30/topic30.html#Exptree
หากคุณไปที่ส่วนแผนภูมินิพจน์จากนั้นเลื่อนหน้าลงเล็กน้อยจะแสดง "การเรียงลำดับโทโพโลยี" ของทรีและอัลกอริทึมสำหรับวิธีประเมินนิพจน์
ดังนั้นในกรณีนี้คุณสามารถใช้ DAG เพื่อประเมินนิพจน์ซึ่งมีประโยชน์เนื่องจากโดยปกติแล้วการประเมินผลจะถูกตีความและการใช้ผู้ประเมิน DAG ดังกล่าวจะทำให้ผู้รวบรวมข้อมูลที่เรียบง่ายเร็วขึ้นในส่วนหลักเนื่องจากไม่ได้ผลักดันและโผล่ไปยังสแต็กและเนื่องจากเป็นการกำจัด นิพจน์ย่อยทั่วไป
อัลกอริทึมพื้นฐานในการคำนวณ DAG ในภาษาอียิปต์ที่ไม่ใช่ภาษาอียิปต์โบราณ (เช่นภาษาอังกฤษ) คือ:
1) ทำให้วัตถุ DAG ของคุณเป็นเช่นนั้น
คุณต้องมีรายการสดและรายการนี้มีโหนด DAG และนิพจน์ย่อย DAG ปัจจุบันทั้งหมด นิพจน์ย่อย DAG คือ DAG Node หรือเรียกอีกอย่างว่าโหนดภายใน สิ่งที่ฉันหมายถึงโดย live DAG Node คือถ้าคุณกำหนดให้กับตัวแปร 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 โดยไม่มีลูกให้กำหนด Node นั้นให้เป็นหมายเลขการเรียงลำดับปัจจุบันและเพิ่มหมายเลขการเรียงลำดับดังนั้นเมื่อการเรียกซ้ำคลายตัวเลขที่ได้รับมอบหมายตามลำดับที่เพิ่มขึ้น
ตัวอย่างนี้จัดการเฉพาะต้นไม้ที่มีโหนดที่มีลูกศูนย์หรือสองลูก เห็นได้ชัดว่าต้นไม้บางต้นมีโหนดที่มีลูกมากกว่าสองลูกดังนั้นตรรกะจึงยังคงเหมือนเดิม แทนที่จะคำนวณซ้ายและขวาให้คำนวณจากซ้ายไปขวาเป็นต้น ...
// 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 ช่วยที่นั่น) แต่สำหรับฉัน DAGs มีประโยชน์อย่างมากเมื่อพิจารณาการอ้างอิงระหว่างทรัพยากร เครื่องมือเกมของฉันแสดงถึงทรัพยากรที่โหลดทั้งหมด (วัสดุพื้นผิวเฉดสีข้อความธรรมดา parsed json ฯลฯ ) เป็น DAG เดียว ตัวอย่าง:
วัสดุคือโปรแกรม N GL ซึ่งแต่ละตัวต้องการเฉดสีสองตัวและแต่ละเฉดสีต้องการแหล่งที่มาของ shader แบบธรรมดา ด้วยการแทนทรัพยากรเหล่านี้เป็น DAG ฉันสามารถสืบค้นกราฟสำหรับทรัพยากรที่มีอยู่ได้อย่างง่ายดายเพื่อหลีกเลี่ยงการโหลดซ้ำ สมมติว่าคุณต้องการให้วัสดุหลายอย่างใช้จุดยอดเฉดสีด้วยซอร์สโค้ดเดียวกัน เป็นการสิ้นเปลืองที่จะโหลดซอร์สใหม่และคอมไพล์เฉดสีใหม่สำหรับการใช้งานทุกครั้งเมื่อคุณสามารถสร้างขอบใหม่ให้กับทรัพยากรที่มีอยู่ได้ ด้วยวิธีนี้คุณสามารถใช้กราฟเพื่อตรวจสอบว่ามีสิ่งใดขึ้นอยู่กับทรัพยากรหรือไม่และถ้าไม่ให้ลบออกและเพิ่มหน่วยความจำในความเป็นจริงสิ่งนี้เกิดขึ้นโดยอัตโนมัติ
โดยส่วนขยาย DAG มีประโยชน์สำหรับการแสดงไปป์ไลน์การประมวลผลข้อมูล ลักษณะทางอ้อมหมายความว่าคุณสามารถเขียนโค้ดการประมวลผลตามบริบทได้อย่างปลอดภัยซึ่งสามารถติดตามตัวชี้ไปตามขอบจากจุดยอดโดยไม่ต้องคำนึงถึงจุดยอดเดียวกันอีกครั้ง ภาษาโปรแกรมภาพเช่นVVVV , Max MSPหรืออินเทอร์เฟซที่ใช้โหนดของ Autodesk Maya ล้วนพึ่งพา DAGs
กราฟอะไซคลิกที่กำหนดทิศทางมีประโยชน์เมื่อคุณต้องการแสดง ... ตัวอย่างที่เป็นที่ยอมรับคือแผนผังครอบครัวหรือลำดับวงศ์ตระกูล