web-dev-qa-db-fra.com

DFS itératif vs DFS récursif et ordre des différents éléments

J'ai écrit un algorithme DFS récursif pour parcourir un graphe:

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);
    }
}

Ensuite, j'ai écrit un algorithme DFS itératif utilisant une pile:

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);
            }
        }
    }

Mon problème est celui d'un graphe dans lequel, par exemple, j'entre les trois nœuds 'a', 'b', 'c' avec des arcs ('a', 'b') et ('a', 'c') ma sortie est:

'a', 'b', 'c' avec la version récursive DFS, et:

'a', 'c', 'b' avec le DFS itératif.

Comment pourrais-je obtenir le même ordre? Est-ce que je fais quelque chose de mal?

Je vous remercie!

36
JohnQ

Les deux sont valides Algorithmes DFS. Un DFS ne spécifie pas quel nœud vous voyez en premier. Ce n'est pas important car l'ordre entre les arêtes n'est pas défini [rappelez-vous: les arêtes sont généralement un ensemble]. La différence est due à la façon dont vous gérez les enfants de chaque nœud.

Dans la approche itérative: vous insérez d’abord tous les éléments dans la pile - et gérez ensuite la tête de la pile [qui est le dernier noeud inséré] - ainsi le premier noeud que vous manipulez est le dernier). enfant.

Dans la approche récursive: vous gérez chaque nœud lorsque vous le voyez. Ainsi, le le premier noeud que vous manipulez est le premier enfant.

Pour que le DFS itératif donne le même résultat que le récursif - vous devez ajouter des éléments à la pile dans l'ordre inverse [[pour chaque nœud, insérez son dernier enfant puis son premier enfant]

62
amit

Vous trouverez ci-dessous un exemple de code (selon la réponse @amit ci-dessus) en C # pour Adjacency Matrix.

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);
                    }
                }
            }
        }
    }
}
0
Sai