यदि एक निर्देशित ग्राफ एसाइक्लिक है, तो मैं कैसे जांच सकता हूं? और एल्गोरिथ्म को कैसे कहा जाता है? मैं एक संदर्भ की सराहना करूंगा।
यदि एक निर्देशित ग्राफ एसाइक्लिक है, तो मैं कैसे जांच सकता हूं? और एल्गोरिथ्म को कैसे कहा जाता है? मैं एक संदर्भ की सराहना करूंगा।
जवाबों:
मैं ग्राफ़ को स्थैतिक रूप से क्रमबद्ध करने की कोशिश करूंगा , और यदि आप नहीं कर सकते हैं, तो इसमें चक्र हैं।
एक सरल गहराई-पहली-खोज करना एक चक्र खोजने के लिए पर्याप्त नहीं है। मौजूदा चक्र के बिना डीएफएस में कई बार नोड का दौरा करना संभव है। आप कहाँ से शुरू करते हैं, इस पर निर्भर करते हुए, आप पूरे ग्राफ़ पर भी नहीं जा सकते हैं।
आप ग्राफ के जुड़े घटक में निम्नानुसार चक्रों की जांच कर सकते हैं। एक नोड खोजें, जिसमें केवल आउटगोइंग किनारे हों। यदि ऐसा कोई नोड नहीं है, तो एक चक्र है। उस नोड पर DFS प्रारंभ करें। प्रत्येक किनारे को ट्रेस करते समय, जांचें कि क्या किनारे पहले से ही आपके स्टैक पर एक नोड को वापस इंगित करता है। यह एक चक्र के अस्तित्व को इंगित करता है। यदि आपको ऐसा कोई किनारा नहीं मिलता है, तो उस जुड़े घटक में कोई चक्र नहीं हैं।
जैसा कि रटर प्रिन्स बताते हैं, यदि आपका ग्राफ जुड़ा नहीं है, तो आपको प्रत्येक जुड़े घटक पर खोज को दोहराना होगा।
एक संदर्भ के रूप में, टारजन का दृढ़ता से जुड़ा घटक एल्गोरिथ्म बारीकी से संबंधित है। यह आपको चक्रों को खोजने में भी मदद करेगा, न कि केवल रिपोर्ट करें कि क्या वे मौजूद हैं।
पुस्तक पर लेम्मा 22.11 Introduction to Algorithms
(दूसरा संस्करण) बताता है कि:
एक निर्देशित ग्राफ जी एसाइक्लिक है अगर और केवल अगर जी की गहराई-पहली खोज से कोई बैक एज नहीं निकलता है
समाधान 1 1 काहन एल्गोरिदम चक्र की जाँच करने के लिए । मुख्य विचार: एक कतार बनाए रखें जहाँ शून्य इन-डिग्री वाले नोड को कतार में जोड़ा जाएगा। फिर नोड को एक-एक करके छीलें जब तक कि कतार खाली न हो जाए। जांचें कि क्या किसी नोड के किनारों में मौजूद हैं।
Solution2 : मजबूत जुड़े घटक की जाँच करने के लिए टारजन एल्गोरिदम ।
Solution3 : DFS । नोड की वर्तमान स्थिति को टैग करने के लिए पूर्णांक सरणी का उपयोग करें: यानी 0 --means यह नोड पहले नहीं देखा गया है। -1 - इसका मतलब है कि इस नोड का दौरा किया गया है, और इसके बच्चों के नोड्स का दौरा किया जा रहा है। 1 - इसका मतलब है कि इस नोड का दौरा किया गया है, और यह हो चुका है। इसलिए यदि DFS करते समय एक नोड की स्थिति -1 है, तो इसका मतलब है कि एक चक्र मौजूद होना चाहिए।
ShuggyCoUk द्वारा दिया गया समाधान अधूरा है क्योंकि यह सभी नोड्स की जाँच नहीं कर सकता है।
def isDAG(nodes V):
while there is an unvisited node v in V:
bool cycleFound = dfs(v)
if cyclefound:
return false
return true
यह समयबद्धता O (n + m) या O (n ^ 2) है
m = O(n^2)
चूंकि पूर्ण ग्राफ में बिल्कुल m=n^2
किनारे हैं। तो वह है O(n+m) = O(n + n^2) = O(n^2)
।
मुझे पता है कि यह एक पुराना विषय है लेकिन भविष्य के खोजकर्ताओं के लिए यहाँ एक C # कार्यान्वयन है जिसे मैंने बनाया (कोई दावा नहीं कि यह सबसे कुशल है)। यह प्रत्येक नोड की पहचान करने के लिए एक साधारण पूर्णांक का उपयोग करने के लिए डिज़ाइन किया गया है। आप अपने नोड ऑब्जेक्ट हैश प्रदान की है और ठीक से बराबरी की तरह है कि हालांकि आप इसे सजाने कर सकते हैं।
बहुत गहरे रेखांकन के लिए यह उच्च ओवरहेड हो सकता है, क्योंकि यह गहराई से प्रत्येक नोड पर एक हैशसेट बनाता है (वे चौड़ाई से अधिक नष्ट हो जाते हैं)।
आप उस नोड को इनपुट करते हैं जिससे आप खोजना चाहते हैं और पथ उस नोड पर ले जाता है।
किसी भी नोड के नीचे चक्रों की जांच करते समय, बस उस नोड को खाली हैशसेट के साथ पास करें
private bool FindCycle(int node, HashSet<int> path)
{
if (path.Contains(node))
return true;
var extendedPath = new HashSet<int>(path) {node};
foreach (var child in GetChildren(node))
{
if (FindCycle(child, extendedPath))
return true;
}
return false;
}
यदि ग्राफ़ में चक्र है, तो यह जानने के लिए एक तेज़ कोड है:
func isCyclic(G : Dictionary<Int,Array<Int>>,root : Int , var visited : Array<Bool>,var breadCrumb : Array<Bool>)-> Bool
{
if(breadCrumb[root] == true)
{
return true;
}
if(visited[root] == true)
{
return false;
}
visited[root] = true;
breadCrumb[root] = true;
if(G[root] != nil)
{
for child : Int in G[root]!
{
if(isCyclic(G,root : child,visited : visited,breadCrumb : breadCrumb))
{
return true;
}
}
}
breadCrumb[root] = false;
return false;
}
let G = [0:[1,2,3],1:[4,5,6],2:[3,7,6],3:[5,7,8],5:[2]];
var visited = [false,false,false,false,false,false,false,false,false];
var breadCrumb = [false,false,false,false,false,false,false,false,false];
var isthereCycles = isCyclic(G,root : 0, visited : visited, breadCrumb : breadCrumb)
विचार इस तरह है: एक सामान्य dfs एल्गोरिथ्म के साथ एक सरणी के साथ विज़िट किए गए नोड्स का ट्रैक रखने के लिए, और एक अतिरिक्त सरणी जो नोड्स के लिए एक मार्कर के रूप में कार्य करता है जो वर्तमान नोड के लिए नेतृत्व करता है, ताकि जब हम कभी भी नोड के लिए dfs निष्पादित करें। हम मार्कर के सरणी में इसके संबंधित आइटम को सही के रूप में सेट करते हैं, ताकि जब कभी पहले से विज़िट किए गए नोड का सामना करना पड़े, तो हम जांच लें कि मार्कर सरणी में इसका संबंधित आइटम सही है या नहीं, यदि इसका सही है तो इसकी नोड्स में से एक जो खुद को देना है (इसलिए चक्र), और चाल यह है कि जब भी एक नोड का dfs वापस आता है तो हम इसके संबंधित मार्कर को गलत पर सेट करते हैं, ताकि यदि हम इसे फिर से किसी अन्य मार्ग से देखें तो हम मूर्ख न बनें।
Google इंटरव्यू में बस यही सवाल था।
आप टोपोलॉजिकल रूप से सॉर्ट करने का प्रयास कर सकते हैं, जो कि O (V + E) है जहां V वर्टिकल की संख्या है, और E किनारों की संख्या है। एक निर्देशित ग्राफ एसाइक्लिक है यदि और केवल यदि यह किया जा सकता है।
पुनरावर्ती पत्ती नोड्स को तब तक हटा दें जब तक कि कोई भी न बचा हो, और यदि आपके पास एक चक्र से अधिक एकल नोड बचा है, तो। जब तक मैं गलत नहीं हूँ, यह O (V ^ 2 + VE) है।
हालांकि, एक कुशल DFS-esque एल्गोरिथम, सबसे खराब स्थिति O (V + E) है:
function isAcyclic (root) {
const previous = new Set();
function DFS (node) {
previous.add(node);
let isAcyclic = true;
for (let child of children) {
if (previous.has(node) || DFS(child)) {
isAcyclic = false;
break;
}
}
previous.delete(node);
return isAcyclic;
}
return DFS(root);
}
यहाँ छील बंद पत्ती नोड एल्गोरिथ्म का मेरा रूबी कार्यान्वयन है ।
def detect_cycles(initial_graph, number_of_iterations=-1)
# If we keep peeling off leaf nodes, one of two things will happen
# A) We will eventually peel off all nodes: The graph is acyclic.
# B) We will get to a point where there is no leaf, yet the graph is not empty: The graph is cyclic.
graph = initial_graph
iteration = 0
loop do
iteration += 1
if number_of_iterations > 0 && iteration > number_of_iterations
raise "prevented infinite loop"
end
if graph.nodes.empty?
#puts "the graph is without cycles"
return false
end
leaf_nodes = graph.nodes.select { |node| node.leaving_edges.empty? }
if leaf_nodes.empty?
#puts "the graph contain cycles"
return true
end
nodes2 = graph.nodes.reject { |node| leaf_nodes.member?(node) }
edges2 = graph.edges.reject { |edge| leaf_nodes.member?(edge.destination) }
graph = Graph.new(nodes2, edges2)
end
raise "should not happen"
end
आप मेरे उत्तर से चक्र खोजने के व्युत्क्रम का उपयोग कर सकते हैं यहां https://stackoverflow.com/a/60196714/1763149
def is_acyclic(graph):
return not has_cycle(graph)