האלגוריתם של הירולצר לגרף מכוון

האלגוריתם של הירולצר לגרף מכוון

בהינתן גרף אוילר מכוון המשימה היא להדפיס מעגל אוילר . מעגל אוילר הוא נתיב שחוצה כל קצה של גרף פעם אחת בדיוק והנתיב מסתיים בקודקוד ההתחלה.

פֶּתֶק: הגרף הנתון מכיל מעגל אוילר.

דוּגמָה:



קלט: גרף מכוון

האלגוריתם של הירולצר לגרף מכוון

תְפוּקָה: 0 3 4 0 2 1 0

דרישות קדם:

  • דנו ב בעיה של לגלות אם גרף נתון הוא אולריאן או לא עבור גרף לא מכוון
  • תנאים למעגל אולריאנית ב-Grpag מכוון: (1) כל הקודקודים שייכים לרכיב אחד מחובר חזק. (2) לכל הקודקודים יש אותה מעלה ודרגה החוצה. שימו לב שעבור גרף לא מכוון התנאי שונה (לכל הקודקודים יש מידה שווה)

גִישָׁה:

  1. בחרו כל קודקוד התחלתי v ועקבו אחרי שובל של קצוות מאותו קודקוד עד החזרה ל-v. לא ניתן להיתקע בשום קודקוד פרט ל-v כי דרגת דרגת קצה של כל קודקוד חייבת להיות זהה כאשר השביל נכנס לקודקוד אחר w חייב להיות קצה לא בשימוש שיוצא מ-w. הסיור שנוצר בדרך זו הוא סיור סגור אך עשוי שלא לכסות את כל הקודקודים והקצוות של הגרף הראשוני.
  2. כל עוד קיים קודקוד u ששייך לסיור הנוכחי אך יש לו קצוות סמוכים שאינם חלק מהסיור התחילו מסלול נוסף מ-u בעקבות קצוות לא בשימוש עד החזרה אל u והצטרפו לסיור שנוצר בצורה זו לסיור הקודם.

אִיוּר:

ניקח דוגמה לתרשים שלמעלה עם 5 צמתים: adj = {{2 3} {0} {1} {4} {0}}.

  1. התחל בקודקוד 0 :
    • נתיב נוכחי: [0]
    • מעגל: []
  2. קודקוד 0 → 3 :
    • נתיב נוכחי: [0 3]
    • מעגל: []
  3. קודקוד 3 → 4 :
    • נתיב נוכחי: [0 3 4]
    • מעגל: []
  4. קודקוד 4 → 0 :
    • נתיב נוכחי: [0 3 4 0]
    • מעגל: []
  5. קודקוד 0 → 2 :
    • נתיב נוכחי: [0 3 4 0 2]
    • מעגל: []
  6. קודקוד 2 → 1 :
    • נתיב נוכחי: [0 3 4 0 2 1]
    • מעגל: []
  7. קודקוד 1 → 0 :
    • נתיב נוכחי: [0 3 4 0 2 1 0]
    • מעגל: []
  8. חזרה לקודקוד 0 : הוסף 0 למעגל.
    • נתיב נוכחי: [0 3 4 0 2 1]
    • מעגל: [0]
  9. חזרה לקודקוד 1 : הוסף 1 למעגל.
    • נתיב נוכחי: [0 3 4 0 2]
    • מעגל: [0 1]
  10. חזרה לקודקוד 2 : הוסף 2 למעגל.
    • נתיב נוכחי: [0 3 4 0]
    • מעגל: [0 1 2]
  11. חזרה לקודקוד 0 : הוסף 0 למעגל.
    • נתיב נוכחי: [0 3 4]
    • מעגל: [0 1 2 0]
  12. חזרה לקודקוד 4 : הוסף 4 למעגל.
    • נתיב נוכחי: [0 3]
    • מעגל: [0 1 2 0 4]
  13. חזרה לקודקוד 3 : הוסף 3 למעגל.
    • נתיב נוכחי: [0]
    • מעגל: [0 1 2 0 4 3]
  14. חזרה לקודקוד 0 : הוסף 0 למעגל.
    • נתיב נוכחי: []
    • מעגל: [0 1 2 0 4 3 0]

להלן היישום של הגישה לעיל: 

C++
   // C++ program to print Eulerian circuit in given   // directed graph using Hierholzer algorithm   #include          using     namespace     std  ;   // Function to print Eulerian circuit   vector   <  int  >     printCircuit  (  vector   <  vector   <  int  >>     &  adj  )     {      int     n     =     adj  .  size  ();      if     (  n     ==     0  )      return     {};      // Maintain a stack to keep vertices      // We can start from any vertex here we start with 0      vector   <  int  >     currPath  ;      currPath  .  push_back  (  0  );      // list to store final circuit      vector   <  int  >     circuit  ;      while     (  currPath  .  size  ()     >     0  )     {      int     currNode     =     currPath  [  currPath  .  size  ()     -     1  ];      // If there's remaining edge in adjacency list      // of the current vertex      if     (  adj  [  currNode  ].  size  ()     >     0  )     {          // Find and remove the next vertex that is      // adjacent to the current vertex      int     nextNode     =     adj  [  currNode  ].  back  ();      adj  [  currNode  ].  pop_back  ();      // Push the new vertex to the stack      currPath  .  push_back  (  nextNode  );      }      // back-track to find remaining circuit      else     {      // Remove the current vertex and      // put it in the circuit      circuit  .  push_back  (  currPath  .  back  ());      currPath  .  pop_back  ();      }      }      // reverse the result vector       reverse  (  circuit  .  begin  ()     circuit  .  end  ());          return     circuit  ;   }   int     main  ()     {      vector   <  vector   <  int  >>     adj     =     {{  2       3  }     {  0  }     {  1  }     {  4  }     {  0  }};      vector   <  int  >     ans     =     printCircuit  (  adj  );          for     (  auto     v  :     ans  )     cout      < <     v      < <     ' '  ;      cout      < <     endl  ;      return     0  ;   }   
Java
   // Java program to print Eulerian circuit in given   // directed graph using Hierholzer algorithm   import     java.util.*  ;   class   GfG     {      // Function to print Eulerian circuit      static     List   <  Integer  >     printCircuit  (  List   <  List   <  Integer  >>     adj  )     {      int     n     =     adj  .  size  ();      if     (  n     ==     0  )      return     new     ArrayList   <>  ();      // Maintain a stack to keep vertices      // We can start from any vertex here we start with 0      List   <  Integer  >     currPath     =     new     ArrayList   <>  ();      currPath  .  add  (  0  );      // list to store final circuit      List   <  Integer  >     circuit     =     new     ArrayList   <>  ();      while     (  currPath  .  size  ()     >     0  )     {      int     currNode     =     currPath  .  get  (  currPath  .  size  ()     -     1  );      // If there's remaining edge in adjacency list      // of the current vertex      if     (  adj  .  get  (  currNode  ).  size  ()     >     0  )     {      // Find and remove the next vertex that is      // adjacent to the current vertex      int     nextNode     =     adj  .  get  (  currNode  ).  get  (  adj  .  get  (  currNode  ).  size  ()     -     1  );      adj  .  get  (  currNode  ).  remove  (  adj  .  get  (  currNode  ).  size  ()     -     1  );      // Push the new vertex to the stack      currPath  .  add  (  nextNode  );      }      // back-track to find remaining circuit      else     {      // Remove the current vertex and      // put it in the circuit      circuit  .  add  (  currPath  .  get  (  currPath  .  size  ()     -     1  ));      currPath  .  remove  (  currPath  .  size  ()     -     1  );      }      }      // reverse the result vector      Collections  .  reverse  (  circuit  );      return     circuit  ;      }      public     static     void     main  (  String  []     args  )     {      List   <  List   <  Integer  >>     adj     =     new     ArrayList   <>  ();      adj  .  add  (  new     ArrayList   <>  (  Arrays  .  asList  (  2       3  )));      adj  .  add  (  new     ArrayList   <>  (  Arrays  .  asList  (  0  )));         adj  .  add  (  new     ArrayList   <>  (  Arrays  .  asList  (  1  )));         adj  .  add  (  new     ArrayList   <>  (  Arrays  .  asList  (  4  )));         adj  .  add  (  new     ArrayList   <>  (  Arrays  .  asList  (  0  )));         List   <  Integer  >     ans     =     printCircuit  (  adj  );      for     (  int     v     :     ans  )     System  .  out  .  print  (  v     +     ' '  );      System  .  out  .  println  ();      }   }   
Python
   # Python program to print Eulerian circuit in given   # directed graph using Hierholzer algorithm   # Function to print Eulerian circuit   def   printCircuit  (  adj  ):   n   =   len  (  adj  )   if   n   ==   0  :   return   []   # Maintain a stack to keep vertices   # We can start from any vertex here we start with 0   currPath   =   [  0  ]   # list to store final circuit   circuit   =   []   while   len  (  currPath  )   >   0  :   currNode   =   currPath  [  -  1  ]   # If there's remaining edge in adjacency list   # of the current vertex   if   len  (  adj  [  currNode  ])   >   0  :   # Find and remove the next vertex that is   # adjacent to the current vertex   nextNode   =   adj  [  currNode  ]  .  pop  ()   # Push the new vertex to the stack   currPath  .  append  (  nextNode  )   # back-track to find remaining circuit   else  :   # Remove the current vertex and   # put it in the circuit   circuit  .  append  (  currPath  .  pop  ())   # reverse the result vector   circuit  .  reverse  ()   return   circuit   if   __name__   ==   '__main__'  :   adj   =   [[  2     3  ]   [  0  ]   [  1  ]   [  4  ]   [  0  ]]   ans   =   printCircuit  (  adj  )   for   v   in   ans  :   print  (  v     end  =  ' '  )   print  ()   
C#
   // C# program to print Eulerian circuit in given   // directed graph using Hierholzer algorithm   using     System  ;   using     System.Collections.Generic  ;   class     GfG     {          // Function to print Eulerian circuit      static     List   <  int  >     printCircuit  (  List   <  List   <  int  >>     adj  )     {      int     n     =     adj  .  Count  ;      if     (  n     ==     0  )      return     new     List   <  int  >  ();      // Maintain a stack to keep vertices      // We can start from any vertex here we start with 0      List   <  int  >     currPath     =     new     List   <  int  >     {     0     };      // list to store final circuit      List   <  int  >     circuit     =     new     List   <  int  >  ();      while     (  currPath  .  Count     >     0  )     {      int     currNode     =     currPath  [  currPath  .  Count     -     1  ];      // If there's remaining edge in adjacency list      // of the current vertex      if     (  adj  [  currNode  ].  Count     >     0  )     {      // Find and remove the next vertex that is      // adjacent to the current vertex      int     nextNode     =     adj  [  currNode  ][  adj  [  currNode  ].  Count     -     1  ];      adj  [  currNode  ].  RemoveAt  (  adj  [  currNode  ].  Count     -     1  );      // Push the new vertex to the stack      currPath  .  Add  (  nextNode  );      }      // back-track to find remaining circuit      else     {      // Remove the current vertex and      // put it in the circuit      circuit  .  Add  (  currPath  [  currPath  .  Count     -     1  ]);      currPath  .  RemoveAt  (  currPath  .  Count     -     1  );      }      }      // reverse the result vector      circuit  .  Reverse  ();      return     circuit  ;      }      static     void     Main  (  string  []     args  )     {      List   <  List   <  int  >>     adj     =     new     List   <  List   <  int  >>     {      new     List   <  int  >     {     2       3     }      new     List   <  int  >     {     0     }      new     List   <  int  >     {     1     }      new     List   <  int  >     {     4     }      new     List   <  int  >     {     0     }      };      List   <  int  >     ans     =     printCircuit  (  adj  );      foreach     (  int     v     in     ans  )     {      Console  .  Write  (  v     +     ' '  );      }      Console  .  WriteLine  ();      }   }   
JavaScript
   // JavaScript program to print Eulerian circuit in given   // directed graph using Hierholzer algorithm   // Function to print Eulerian circuit   function     printCircuit  (  adj  )     {      let     n     =     adj  .  length  ;      if     (  n     ===     0  )      return     [];      // Maintain a stack to keep vertices      // We can start from any vertex here we start with 0      let     currPath     =     [  0  ];      // list to store final circuit      let     circuit     =     [];      while     (  currPath  .  length     >     0  )     {      let     currNode     =     currPath  [  currPath  .  length     -     1  ];      // If there's remaining edge in adjacency list      // of the current vertex      if     (  adj  [  currNode  ].  length     >     0  )     {      // Find and remove the next vertex that is      // adjacent to the current vertex      let     nextNode     =     adj  [  currNode  ].  pop  ();      // Push the new vertex to the stack      currPath  .  push  (  nextNode  );      }      // back-track to find remaining circuit      else     {      // Remove the current vertex and      // put it in the circuit      circuit  .  push  (  currPath  .  pop  ());      }      }      // reverse the result vector      circuit  .  reverse  ();      return     circuit  ;   }   let     adj     =     [[  2       3  ]     [  0  ]     [  1  ]     [  4  ]     [  0  ]];   let     ans     =     printCircuit  (  adj  );   for     (  let     v     of     ans  )     {      console  .  log  (  v       ' '  );   }   

תְפוּקָה
0 3 4 0 2 1 0  

מורכבות זמן:  O(V + E) כאשר V הוא מספר הקודקודים ו-E הוא מספר הקצוות בגרף. הסיבה לכך היא כי האלגוריתם מבצע חיפוש עומק ראשון (DFS) ומבקר בכל קודקוד ובכל קצה בדיוק פעם אחת. אז לכל קודקוד לוקח זמן O(1) לבקר אותו ולכל קצה לוקח זמן O(1) לחצות אותו.

מורכבות החלל  : O(V + E) כפי שהאלגוריתם משתמש במחסנית לאחסון הנתיב הנוכחי וברשימה לאחסון המעגל הסופי. הגודל המקסימלי של הערימה יכול להיות V + E במקרה הגרוע ולכן מורכבות החלל היא O(V + E).

צור חידון

מאמרים למעלה

קטגוריה

מאמרים מעניינים