在C ++中使用STL实现DFS时遇到分段错误

时间:2016-06-16 06:03:21

标签: c++ algorithm graph stl depth-first-search

调试分段错误是我作为C ++初学者所面临的关键问题之一。我曾尝试在以下代码行中使用C ++ STL实现有向图中的深度优先搜索(基于Steven Skienna的算法设计手册):

    #include <iostream>
    #include <list>
    #include <cstdio>


    using namespace std;

    #define TREE        0       /* tree edge */
    #define BACK        1       /* back edge */
    #define CROSS       2       /* cross edge */
    #define FORWARD     3       /* forward edge */


    class Graph
    {
        int V; //no of vertices
        int time;
        list <int> *adj; //Pointer to an array containeing the adjacency list

    public:

        Graph(int V); //A constructor 
        int entry_time[] ,exit_time[] , parent[] ;
        bool processed[] , discovered[] ;
        void addEdge(int v , int w ) ; // a function to add an edge to graph 
        void DFS(int v); // print DFS transversal of the complete graph 
        void initializeGraph () ; // a function used by DFS
        void process_edge(int x , int y);
        void process_vertex_early(int x);
        void process_vertex_late(int x);
        int edge_classification(int x , int y);
    };

    Graph::Graph(int V)
    {
        this->V = V;
        adj = new list<int>[V]; //  dynamic allocation of V lists to an array named adj
    }

    void Graph::addEdge(int v, int w )
    {
        adj[v].push_back(w); //Add w to v's list
    }

    void Graph::initializeGraph ()
    {

        time = 0;

        for (int j=0;j<V;j++)
            {
                processed[j]=discovered[j] = false;
                parent[j]=-1;
            }

        // Recur for all the vertices adjacent to this vertex
    }

    void Graph::DFS(int v)
    {   

        process_vertex_early(v);
        list <int>::iterator i  ;


        for (i=(adj[v].begin());i!=adj[v].end();++i) 
        {   cout << *i ;
            if (discovered[*i]==false)
                {
                    parent[*i] = v ;
                    process_edge(v,*i);
                    DFS(*i);
                }
            else if (processed[*i]==false)
                    process_edge(v,*i);

        }

        process_vertex_late(v);


    }

    void Graph::process_vertex_early(int v)
    {
        discovered[v] = true;
        time = time +1 ; 
        entry_time[v] = time ;
        printf("discovered vertex %d at time %d\n",v, entry_time[v]);
    }

    void Graph::process_vertex_late(int v)
    {
        time = time + 1 ;
        exit_time[v] = time; 
        processed[v] = true;
        //printf("processed vertex %d at time %d\n",v, exit_time[v]);

    } 

    int Graph::edge_classification (int x , int y )
    {
        if (parent[y]==x) return (TREE);
        if (discovered[y] && !processed[y]) return (BACK);


        //cout << " Warning : self loop " << x << y ; 
    }

    void Graph::process_edge(int x , int y)
    {   
        int type ;

        type = edge_classification(x,y);

        //if (type== BACK) cout << "Back Edge" << x << " -> " << y << endl;
        //else if (type== TREE) cout << "Tree Edge" << x << " -> " << y << endl;
        //else cout << " Not in the type " ; 

    }


    int  main()
    {
        Graph g(4);
        g.initializeGraph();
        g.addEdge(0,1);
        g.addEdge(0,2);
        g.addEdge(1,2);
        g.addEdge(2,0);
        g.addEdge(2,3);
        g.addEdge(3,1);

        cout << " Following is a DFS transversal \n " ;
        g.DFS(0);
        return 0;
    }

在搜索操作达到一个或两个深度后发生分段错误。我曾尝试使用类似的语法来应用广度优先搜索。请帮我调试这段代码。谢谢。

1 个答案:

答案 0 :(得分:3)

第一步是阅读所有编译器警告(并在打开警告的情况下编译)。

例如:

   int entry_time[] ,exit_time[] , parent[] ;

这些数组的定义没有大小 - 但您要将数据放入其中。这意味着您在数组边界之外写入会导致未定义的行为(例如您看到的崩溃和双重释放)。像为adj那样为这些数组分配空间,或者使用另一个容器(例如vector),您可以根据需要调整其大小。

同样edge_classification并不总是返回一个值 - 你的编译器应该警告过你。

修改:有关std::vector

的更多信息

您无法将数组声明为entry_time[V],因为在编译时不知道V的值。您可以拥有许多不同大小的Graph个对象。

如果您将数组更改为std::vector,则可以在Graph构造函数中分配它们的大小,让std::vector类担心分配和释放内存。

例如:

在课程中将entry_time声明为std:vector

std::vector<int> entry_time;

在构造函数中,设置entry_time向量的大小。

entry_time.resize(V);

请注意,您可以在此处使用V作为参数来调整大小,因为它在运行时已经有了值。

std::vector具有类似于数组的普通访问器,因此您可以像对待数组一样将值分配给向量的条目。例如,您现有的代码仍然有效:

entry_time[v] = time ;