2012-02-08 10 views
32

मैं एक पुनरावर्ती डीएफएस एल्गोरिथ्म लिखा है एक ग्राफ पार करने के लिए:Iterative डीएफएस बनाम रिकर्सिव डीएफएस और विभिन्न तत्वों के आदेश

template <typename E, typename N> 
void Graph<E, N>::IterativeDFS(Node n) 
{ 
    Stack<Node> stack; 

    stack.Push(n); 

    while(!stack.IsEmpty()) 
    { 
     Node u = stack.Read(); 

     stack.Pop(); 

     if(!IsMarked(u)) 
     { 
      std::cout << ReadNode(u) << " "; 

      MarkVisited(u); 

      NodeList adjnodes = Adjacent(u); 

      NodeList::position pos = adjnodes.FirstPosition(); 

      while(!adjnodes.End(pos)) 
      { 
       stack.Push(adjnodes.ReadList(pos)); 

       pos = adjnodes.NextPosition(pos); 
      } 
     } 
    } 

:

void Graph<E, N>::DFS(Node n) 
{ 
    std::cout << ReadNode(n) << " "; 

    MarkVisited(n); 

    NodeList adjnodes = Adjacent(n); 

    NodeList::position pos = adjnodes.FirstPosition(); 

    while(!adjnodes.End(pos)) 
    { 
     Node adj = adjnodes.ReadList(pos); 

     if(!IsMarked(adj)) 
      DFS(adj); 

     pos = adjnodes.NextPosition(pos); 
    } 
} 

तो मैं एक ढेर का उपयोग कर एक सतत डीएफएस एल्गोरिथ्म लिखा है मेरी समस्या यह है कि एक ग्राफ में, उदाहरण के लिए, मैं तीन नोड्स 'ए', 'बी', 'सी' आर्क्स ('ए', 'बी') और ('ए', 'सी') के साथ दर्ज करता हूं मेरा आउटपुट है:

'ए', 'बी', 'सी' रिकर्सिव डीएफएस संस्करण के साथ , और:

'ए', 'सी', 'बी' पुनरावर्तक डीएफएस एक के साथ।

मुझे वही आदेश कैसे मिल सकता है? क्या मुझसे कुछ गलत हो रही है?

धन्यवाद!

+0

दोनों ऑर्डर वैध डीएफएस ऑर्डरिंग हैं, क्योंकि नोड्स 'बी' और 'सी' नोड 'ए' से एक हॉप में पहुंच योग्य हैं। क्या आप चिंतित हैं कि यह एक अवैध आदेश दे रहा है? या आप सिर्फ दो एल्गोरिदम चाहते हैं - जिनमें से दोनों वैध ऑर्डरिंग उत्पन्न करते हैं - एक ही ऑर्डरिंग के लिए? – templatetypedef

+1

मुझे पता है कि एक ढेर का उपयोग करके मैं एक पुनरावर्ती तरीके से एक पुनरावर्ती कार्य अनुकरण करने में सक्षम होना चाहिए, तो मुझे एक ही आउटपुट क्यों नहीं मिलता है? – JohnQ

उत्तर

57

दोनों मान्य डीएफएस एल्गोरिदम हैं। एक डीएफएस निर्दिष्ट नहीं करता कि आप कौन सा नोड पहले देखते हैं। यह महत्वपूर्ण नहीं है क्योंकि किनारों के बीच क्रम परिभाषित नहीं किया गया है [याद रखें: किनारों आमतौर पर एक सेट होते हैं]। अंतर प्रत्येक नोड के बच्चों को संभालने के तरीके के कारण होता है।

पुनरावृत्ति दृष्टिकोण में: आप पहले सभी तत्वों ढेर में डालने - और फिर ढेर के सिर [जो पिछले नोड डाला है] संभाल - इस प्रकार प्रथम नोड आप को संभाल अंतिम संतान है ।

रिकर्सिव दृष्टिकोण: जब आप इसे देखते हैं तो आप प्रत्येक नोड को संभालते हैं। इस प्रकार आपके द्वारा संभाला जाने वाला पहला नोड पहला बच्चा है।

पुनरावृत्ति डीएफएस पुनरावर्ती एक के रूप में एक ही परिणाम उपज करें - आप की जरूरत उलटे क्रम [प्रत्येक नोड के लिए, अपने पिछले बच्चे पहले अपने पहले बच्चे पिछले डालें और]

+0

ओह, मैं समझता हूं। तो यह सही क्रम में स्टैक में तत्वों को धक्का देने के बारे में है। मैंने अंतिम तत्व से सूची को पहले पढ़ने की कोशिश की है और अब यह काम करता है। धन्यवाद! – JohnQ

+0

@ जॉनक्यू: आपका स्वागत है। मुझे खुशी है कि इससे आपकी मदद मिली, और मुझे उम्मीद है कि आप इन मुद्दों को ठीक करने के लिए * कैसे * समझते हैं, बल्कि यह क्यों हुआ और भविष्य में इसे कैसे पहचानें। – amit

+0

हां, ज़ाहिर है। मैंने स्थिति को समझने के लिए कुछ योजनाएं तैयार की हैं :) – JohnQ

1
में ढेर करने के लिए तत्वों को जोड़ने

नीचे एडजेंसी मैट्रिक्स के लिए सी # में नमूना कोड (ऊपर @amit उत्तर के अनुसार) है।

using System; 
using System.Collections.Generic; 

namespace GraphAdjMatrixDemo 
{ 
    public class Program 
    { 
     public static void Main(string[] args) 
     { 
      // 0 1 2 3 4 5 6 
      int[,] matrix = {  {0, 1, 1, 0, 0, 0, 0}, 
            {1, 0, 0, 1, 1, 1, 0}, 
            {1, 0, 0, 0, 0, 0, 1}, 
            {0, 1, 0, 0, 0, 0, 1}, 
            {0, 1, 0, 0, 0, 0, 1}, 
            {0, 1, 0, 0, 0, 0 ,0}, 
            {0, 0, 1, 1, 1, 0, 0} }; 

      bool[] visitMatrix = new bool[matrix.GetLength(0)]; 
      Program ghDemo = new Program(); 

      for (int lpRCnt = 0; lpRCnt < matrix.GetLength(0); lpRCnt++) 
      { 
       for (int lpCCnt = 0; lpCCnt < matrix.GetLength(1); lpCCnt++) 
       { 
        Console.Write(string.Format(" {0} ", matrix[lpRCnt, lpCCnt])); 
       } 
       Console.WriteLine(); 
      } 

      Console.Write("\nDFS Recursive : "); 
      ghDemo.DftRecursive(matrix, visitMatrix, 0); 
      Console.Write("\nDFS Iterative : "); 
      ghDemo.DftIterative(matrix, 0); 

      Console.Read(); 
     } 

     //==================================================================================================================================== 

     public void DftRecursive(int[,] srcMatrix, bool[] visitMatrix, int vertex) 
     { 
      visitMatrix[vertex] = true; 
      Console.Write(vertex + " "); 

      for (int neighbour = 0; neighbour < srcMatrix.GetLength(0); neighbour++) 
      { 
       if (visitMatrix[neighbour] == false && srcMatrix[vertex, neighbour] == 1) 
       { 
        DftRecursive(srcMatrix, visitMatrix, neighbour); 
       } 
      } 
     } 

     public void DftIterative(int[,] srcMatrix, int srcVertex) 
     { 
      bool[] visited = new bool[srcMatrix.GetLength(0)]; 

      Stack<int> vertexStack = new Stack<int>(); 
      vertexStack.Push(srcVertex); 

      while (vertexStack.Count > 0) 
      { 
       int vertex = vertexStack.Pop(); 

       if (visited[vertex]) 
        continue; 

       Console.Write(vertex + " "); 
       visited[vertex] = true; 

       for (int neighbour = srcMatrix.GetLength(0) - 1; neighbour >= 0; neighbour--) 
       //for (int neighbour = 0; neighbour < srcMatrix.GetLength(0); neighbour++) 
       { 
        if (srcMatrix[vertex, neighbour] == 1 && visited[neighbour] == false) 
        { 
         vertexStack.Push(neighbour); 
        } 
       } 
      } 
     } 
    } 
} 
+1

आपका कोड गलत तरीके से करता है। ध्यान दें कि मेरे उत्तरों ने आपको केवल ** PUSH ** रिवर्स ऑर्डर में तत्वों की आवश्यकता है, जबकि वास्तव में आप अपने कोड में 2 और चीजें करते हैं: (1) उस स्थान को बदलें जहां "विज़िट किया गया था "चेक किया गया है। (2) उस स्थान को बदलें जहां तत्व मुद्रित है (आपके कोड में: जब यह सूची में डाला गया है, और जब इसे से पॉप किया गया है)। मैंने अपना कोड लिया और उपरोक्त दो प्रवाहों को ठीक किया, यह [ideone] (https://ideone.com/OW7JhS) में उपलब्ध है, और ठीक से काम कर रहा है। उम्मीद है कि मुझे किसी अन्य मुद्दे को याद नहीं आया। – amit

+0

विस्तारित करने के लिए: (1): रिकर्सिव कॉल नोड को खोजने पर 'विज़िट' सेट करता है, और नोड डालने पर पुनरावृत्ति कोड सेट करता है। (2) के बारे में: रिकर्सिव कॉल में प्रिंट तब होता है जब नोड का पता लगाया जाता है (ढेर से पॉप किया जाता है), और जब इसे स्टैक करने के लिए धक्का दिया जाता है तो पुनरावृत्त होता है। यदि आप उपरोक्त चेतावनी के प्रत्येक संस्करण के साथ एक के साथ दो पुनरावर्ती समाधानों का प्रयास करते हैं तो उन दो अंतरों से अलग-अलग परिणाम सामने आएंगे। – amit

+0

त्वरित उत्तर के लिए धन्यवाद और मुझे @amit को सही करने के लिए धन्यवाद। जैसा कि आपने बताया है, मैंने लगभग वही किया है (नवीनतम स्थान पर मिस्ड) और मेरे कोड में जो तर्क मैं लापता था, वह है (अगर [vertex] == सत्य देखा गया) जारी रखें; मैंने आपके उत्तर और टिप्पणी को वोट दिया :) और दूसरों के लिए मैट्रिक्स उदाहरण के लिए मेरा उत्तर अपडेट किया। – Sai

संबंधित मुद्दे