web-dev-qa-db-ja.com

反復DFSと再帰DFSおよび異なる要素の順序

グラフを横断する再帰的なDFSアルゴリズムを作成しました。

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

次に、スタックを使用して反復DFSアルゴリズムを作成しました。

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

私の問題は、たとえば、3つのノード「a」、「b」、「c」をアーク(「a」、「b」)および(「a」、「c」)で入力するグラフ私の出力は次のとおりです。

'a'、 'b'、 'c'、再帰的なDFSバージョン、および:

「a」、「c」、「b」と反復DFSの1つ。

どうすれば同じ注文を取得できますか?私は何か間違っていますか?

ありがとうございました!

39
JohnQ

両方とも有効 DFSアルゴリズム。 DFSは、最初に表示されるノードを指定しません。エッジ間の順序は定義されていないため、重要ではありません[通常、エッジはセットです]。違いは、各ノードの子を処理する方法によるものです。

反復アプローチ:最初にすべての要素を挿入するをスタックに挿入し、次にスタックの先頭[挿入された最後のノード]を処理するため、最初に処理するノードは最後の子

再帰的アプローチの場合:表示されたときに各ノードを処理します。したがって、処理する最初のノードは最初の子です。

反復DFSの結果を再帰的なものと同じにするには、要素を逆順にスタックに追加する [各ノードについて、最後の子を最初に、最初の子を最後に挿入する]必要があります

68
amit

ここで、ソリューションを再帰的に残し、非常に高速に実装します。このアルゴリズムの使用を必要とする問題に合わせて調整するだけです。

現在の状態を訪問済みとしてマークすることは非常に重要です。ok[u] = trueとして定義され、memset(ok, 0, sizeof ok)を使用して訪問されていないすべての状態も含まれます。

#define forn(i , a , b) for(int i=(a);i<(b);i++)

vector<int> arr[10001];
bool ok[10001];

void addE(int u , int v){
  arr[u].Push_back(v);
  arr[v].Push_back(u);
}

void dfs(int u){
  ok[u] = true;
  forn(v , 0 , (int)arr[u].size()) if(!ok[arr[u][v]]) dfs(arr[u][v]);
}

int main(){
  //...
  memset(ok , 0 , sizeof ok);
  //... 
  return 0;
}
1
Chris Michael

以下は、隣接行列のC#のサンプルコードです(上記の@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);
                    }
                }
            }
        }
    }
}
0
Sai