рд╕рднреА рдХреЛ рдирдорд╕реНрдХрд╛рд░! рдЕрдЧрд▓реЗ рд╕рдкреНрддрд╛рд╣, рдбреЗрд╡рд▓рдкрд░реНрд╕ рдХреЛрд░реНрд╕ рдХреЗ рд▓рд┐рдП рдПрд▓реНрдЧреЛрд░рд┐рджрдо рдХреЗ рдирдП рд╕рдореВрд╣ рдореЗрдВ рдХрдХреНрд╖рд╛рдПрдВ рд╢реБрд░реВ рд╣реЛ рдЬрд╛рдПрдВрдЧреАред рдЗрд╕ рд╕рдВрдмрдВрдз рдореЗрдВ, рд╣рдо рдЖрдкрдХреЗ рд╕рд╛рде рдПрдХ рдмрд╣реБрдд рдЫреЛрдЯреА, рдмрд▓реНрдХрд┐ рджрд┐рд▓рдЪрд╕реНрдк рд╕рд╛рдордЧреНрд░реА рдХрд╛ рдЕрдиреБрд╡рд╛рдж рд╕рд╛рдЭрд╛ рдХрд░ рд░рд╣реЗ рд╣реИрдВред
рдореИрдВ рдбреЗрдЯрд╛ рд╕рдВрд░рдЪрдирд╛ рдХреЗ рд╕рд╛рде рд▓реЗрдЦреЛрдВ рдХреА рдЗрд╕ рд╢реНрд░реГрдВрдЦрд▓рд╛ рдХреЛ рд╢реБрд░реВ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛ рдЬрд┐рд╕реЗ рд╣рдо рд╕рднреА рдбреЗрд╡рд▓рдкрд░реНрд╕ рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реИрдВ, рд▓реЗрдХрд┐рди рдпрд╣ рд╕рдВрднрд╡ рд╣реИ рдХрд┐ рд╣рдо рдпрд╣ рднреА рдирд╣реАрдВ рдЬрд╛рдирддреЗ рдХрд┐ рдпрд╣ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред
тАЬрджрд┐рд╢рд╛рддреНрдордХ рдЪрдХреНрд░реАрдп рдЧреНрд░рд╛рдл? рдпрд╣ рдХрднреА рдирд╣реАрдВ рд╕реБрдирд╛ред рдРрд╕рд╛ рдордд рд╕реЛрдЪреЛ рдХрд┐ рддреБрдо рдореЗрд░реЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕рдм рдХреБрдЫ рдЬрд╛рдирддреЗ рд╣реЛ! тАЭ, рдЖрдк рдХрд╣ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдпрд╣ рдРрд╕рд╛ рдЧреНрд░рд╛рдл рд╣реИ рдЬреЛ рд╕рдВрд╕реНрдХрд░рдг рдирд┐рдпрдВрддреНрд░рдг рдХреЛ рд╕рдВрднрд╡ рдмрдирд╛рддрд╛ рд╣реИред рд╣рд╛рдБ, рдЧрд┐рдЯ рдПрдХ рдЪрдХреНрд░реАрдп рдЧреНрд░рд╛рдл рд╣реИред рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рдореИрдВ рдЖрдкрдХреЗ рд╕рд╛рде рдбрд╛рдпрд░реЗрдХреНрдЯреЗрдб рдПрд╕рд╛рдЗрдХреНрд▓рд┐рдХ рдЧреНрд░рд╛рдлреНрд╕ (рдбреАрдПрдЬреА) рдХреЗ рдЬреНрдЮрд╛рди рдХреЛ рд╕рд╛рдЭрд╛ рдХрд░реВрдВрдЧрд╛, рдФрд░ рдлрд┐рд░ рдЖрдкрдХреЛ рджрд┐рдЦрд╛рдКрдВрдЧрд╛ рдХрд┐ рдХреИрд╕реЗ рд▓рд┐рдЦрдирд╛ рд╣реИред
DAG рдХреНрдпрд╛ рд╣реИ?
рддреЛ рдЗрд╕рдХрд╛ рдХреНрдпрд╛ рдорддрд▓рдм рд╣реИ? DAG рдПрдХ рдпреВрдирд┐рдбрд╛рдпрд░реЗрдХреНрд╢рдирд▓ рдЧреНрд░рд╛рдл рд╣реИ рдЬрд╣рд╛рдБ рдХрд┐рд╕реА рднреА рддрддреНрд╡ рдХреЛ рдмрдЪреНрдЪрд╛ рдирд╣реАрдВ рдорд╛рдирд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рд╣рдо рдореЗрдВ рд╕реЗ рдХрдИ рд▓реЛрдЧ рд▓рд┐рдВрдХреНрдб рд▓рд┐рд╕реНрдЯ, рдЯреНрд░реА рдФрд░ рдЧреНрд░рд╛рдл рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реИрдВред DAG рддреАрд╕рд░реЗ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдореЗрдВ рдкрд╣рд▓реЗ рдФрд░ рджреВрд╕рд░реЗ рдХреЗ рд╕рдорд╛рди рд╣реИред
рдпрд╣ рдПрдХ рдкреЗрдбрд╝ рдХреА рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдХрд╛рдлреА рдирд╣реАрдВрдЕрдкрдиреЗ рд╕рдмрд╕реЗ рдиреНрдпреВрдирддрдо рд░реВрдк рдореЗрдВ, DAG рдХреЗ 4 рдШрдЯрдХ рд╣реИрдВ:
- рдиреЛрдбреНрд╕ред рд╡реЗ рдбреЗрдЯрд╛ рд╕реНрдЯреЛрд░ рдХрд░рддреЗ рд╣реИрдВред
- рджрд┐рд╢рд╛рддреНрдордХ рдХрд┐рдирд╛рд░рд╛ : рддреАрд░ рдЬреЛ рдПрдХ рджрд┐рд╢рд╛ рдореЗрдВ рдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИ (рдЬреЛ рдЗрд╕ рдбреЗрдЯрд╛ рд╕рдВрд░рдЪрдирд╛ рдХреЛ рдЕрдиреНрдп рдХреЗ рд╡рд┐рдкрд░реАрдд рдмрдирд╛рддрд╛ рд╣реИ)ред
- рдорд╛рддрд╛-рдкрд┐рддрд╛ рдХреЗ рдмрд┐рдирд╛ рдПрдХ "рдорд╣рд╛рди" рдкреВрд░реНрд╡рдЬ рдиреЛрдб ред (рдордЬреЗрджрд╛рд░ рддрдереНрдп: рдЬреНрдпрд╛рджрд╛рддрд░ рдкреВрд░реНрд╡рдЬ рдкреЗрдбрд╝ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЪрдХреНрд░реАрдп рд░реЗрдЦрд╛рдВрдХрди рдирд┐рд░реНрджреЗрд╢рд┐рдд рд╣реЛрддреЗ рд╣реИрдВ, рдкреЗрдбрд╝ рдирд╣реАрдВ, рдХреНрдпреЛрдВрдХрд┐ рдХрднреА-рдХрднреА "рдЪрдЪреЗрд░реЗ рднрд╛рдИ рджреВрд╕рд░реЗ рд╕реЗ рд╢рд╛рджреА рдХрд░рддреЗ рд╣реИрдВ)"
- рдкрддреНрддрд┐рдпрд╛рдВред рдпрд╛ рдмрд┐рдирд╛ рдмрдЪреНрдЪреЗ рдХреЗ рдиреЛрдбреНрд╕ред
рдЖрдЗрдП рд╣рдорд╛рд░рд╛ рдирд┐рд░реНрджреЗрд╢рд┐рдд рдПрд╕рд╛рдЗрдХреНрд▓рд┐рдХ рдЧреНрд░рд╛рдл рд▓рд┐рдЦреЗрдВрдЕрдм рдХреЛрдб рд▓рд┐рдЦрддреЗ рд╣реИрдВред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рджреЛ рдЧреБрдгреЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рдирд┐рд░реНрдорд╛рддрд╛ рдмрдирд╛рдПрдВ рдФрд░ рдЗрд╕реЗ рдбреАрдПрдЬреА рдХрд╣реЗрдВред
function DAG() { this.nodes = []; this.vertices = {}; }
рдиреЛрдбреНрд╕ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд┐рдзрд┐ рдмрдирд╛рдПрдВред рджреЗрдЦрд┐рдпреЗ рдореИрдВрдиреЗ рдпрд╣рд╛рдБ рдХреНрдпрд╛ рдХрд┐рдпрд╛?
DAG.prototype.add = function(node) { if (!node) { return; } if (this.vertices[node]) { return this.vertices[node]; } const vertex = { node: node, incoming: {}, incomingNodes: [], hasOutgoing: false, value: null }; this.vertices[node] = vertex; this.nodes.push(node); return vertex; };
рдпрд╣ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ?
vertex
рдСрдмреНрдЬреЗрдХреНрдЯ рд╡рд╣ рдЬрдЧрд╣ рд╣реИ рдЬрд╣рд╛рдВ рд╕рднреА рдЬрд╛рджреВ рд╣реЛрддрд╛ рд╣реИред рд╣рдо рдПрдХ рдиреЛрдб рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ, рдЖрдиреЗ рд╡рд╛рд▓реА рдиреЛрдбреНрд╕ рдХреЗ рд╕рд╛рде рдПрдХ рдСрдмреНрдЬреЗрдХреНрдЯ, рдФрд░ рдЙрдирдХреЗ рд╕рднреА рдирд╛рдореЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рд╕рд░рдгреА, рдкреНрд░рдХрд╛рд░ рдмреВрд▓рд┐рдпрди рдХрд╛ рдПрдХ рдЪрд░ рдЬреЛ рд╕рдВрдХреЗрдд рджреЗрддрд╛ рд╣реИ рдХрд┐ рдиреЛрдб рдХреБрдЫ рдпрд╛ рдирд╣реАрдВ рдФрд░ рдЗрд╕рдХреЗ рдореВрд▓реНрдп рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИред рд╣рдо рдмрд╛рдж рдореЗрдВ рдЗрд╕ рдкрд░ рдЖрдЧреЗ рдмрдврд╝реЗрдВрдЧреЗред
рдЕрдм рдХреБрдЫ рдХрд┐рдирд╛рд░реЛрдВ рдХреЛ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ рдФрд░ рдиреЛрдбреНрд╕ рдХреЛ рдПрдХ рд╕рд╛рде рдЬреЛрдбрд╝рддреЗ рд╣реИрдВред рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдХрд┐ рд╣рдо рдРрд╕рд╛ рдХрд░ рд╕рдХреЗрдВ, рд╣рдореЗрдВ рдПрдХ рд╕рд╣рд╛рдпрдХ рдлрд╝рдВрдХреНрд╢рди рдмрдирд╛рдирд╛ рд╣реЛрдЧрд╛ рдЬреЛ рдпрд╣ рдЬрд╛рдБрдЪ рдХрд░реЗ рдХрд┐ рд╣рдордиреЗ рдЗрд╕ рдиреЛрдб рдХрд╛ рджреМрд░рд╛ рдХрд┐рдпрд╛ рд╣реИ рдпрд╛ рдирд╣реАрдВред рдЪрд▓реЛ рдЙрд╕рдХреА
visit
рдмреБрд▓рд╛рдУред
function visit(vertex, fn, visited, path) { const name = vertex.name, vertices = vertex.incoming, names = vertex.incomingNames, len = names.length, i; if (!visited) { visited = {}; } if (!path) { path = []; } if (visited.hasOwnProperty(name)) { return; } path.push(name); visited[name] = true; for (i = 0; i < len; i++) { visit(vertices[names[i]], fn, visited, path); } fn(vertex, path); path.pop(); }
рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╣реЛрддрд╛ рд╣реИ:
DAG.prototype.addEdge = function(fromName, toName) { if (!fromName || !toName || fromName === toName) { return; } const from = this.add(fromName) const to = this.add(toName); if (to.incoming.hasOwnProperty(fromName)) { return; } function checkCycle(vertex, path) { if (vertex.name === toName) { throw new Error(тАЬTheres a cycle foo!!!!!тАЬ)); } } visit(from, checkCycle); from.hasOutgoing = true; to.incoming[fromName] = from; to.incomingNames.push(fromName); };
рдпрд╣ рд╢реНрд░рджреНрдзрд╛рдВрдЬрд▓рд┐ рджреЗрдиреЗ рдХрд╛ рд╕рдордп рд╣реИ
рдЬрдм рдореИрдВ рдЗрд╕ рд▓реЗрдЦ рдХреЛ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рд╕рд╛рдордЧреНрд░реА рдХрд╛ рдЕрдзреНрдпрдпрди рдХрд░ рд░рд╣рд╛ рдерд╛, рдореИрдВрдиреЗ рдЖрд╢реНрдЪрд░реНрдпрдЬрдирдХ рд╕реНрдорд╛рд░реНрдЯ рд▓реЛрдЧреЛрдВ рдХреЗ рдХреБрдЫ рдЕрджреНрднреБрдд рд╕рдВрджреЗрд╢ рдкрдврд╝реЗ, рдФрд░ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рдЙрдирдореЗрдВ рд╕реЗ рдЕрдзрд┐рдХрд╛рдВрд╢ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рд╣реБрдИред рдореБрдЭреЗ рдбреАрдПрдЬреА рдФрд░ рд╕рдВрд╕реНрдХрд░рдг рдирд┐рдпрдВрддреНрд░рдг рдкрд░
рдЗрд╕ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рд╕рдВрд░рдЪрд┐рдд рдкреЛрд╕реНрдЯ рд╕реЗ рдХреБрдЫ рд╕реИрджреНрдзрд╛рдВрддрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА рдорд┐рд▓реАред рдпрд╣рд╛рдБ рдкреНрд░рд╕реНрддреБрдд рдХреЛрдб
emberjs рд╕реНрд░реЛрддреЛрдВ рдФрд░ рдЙрдирдХреЗ рд▓реЗрдЦрдХреЛрдВ рд╕реЗ рдкреНрд░реЗрд░рд┐рдд рд╣реИред рдФрд░ рдореИрдВрдиреЗ рдХрдИ рдорд╣рд╛рди рд▓реЛрдЧреЛрдВ рдХреЗ рдмреНрд▓реЙрдЧ рдореЗрдВ рдбреАрдПрдЬреА рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдиреНрдп рд▓реЗрдЦреЛрдВ рдФрд░ рдкреЛрд╕реНрдЯреЛрдВ рд╕реЗ рдмрд╣реБрдд рдХреБрдЫ рд╕реАрдЦрд╛ред
рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж!