【问题标题】:Segmentation Fault encountered while implementation of DFS using STL in C++在 C++ 中使用 STL 实现 DFS 时遇到分段错误
【发布时间】:2016-06-16 06:03:21
【问题描述】:

分段错误的调试是我作为 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;
    }

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

【问题讨论】:

  • 这就是我的想法:entry_time ... 是未指定类型的数组,这是不允许的,但您可能正在使用允许这样做的 gcc/g++。我从来没有使用过这些,但是当我将它们更改为像adj 这样的动态数组时,没有分段错误。
  • 为什么不用std::vector 代替这些非标准的空数组,而std::vector&lt;std::list&lt;int&gt;&gt; 用于邻接列表呢?您正在使用std::list,那么为什么不同时使用std::vector
  • 这是您使用std::vector的代码
  • @PaulMcKenzie 。非常感谢。
  • 嗨@PaulMcKenzie!我正在查看您的代码,但有一些疑问:1)

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


【解决方案1】:

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

例如:

   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 ;

【讨论】:

  • 嗨@The Dark!感谢您的评论 。最初我想定义这些大小为 V 的变量: int entry_time[V] ,exit_time[V] , parent[V] 但编译器给了我其中两个错误 1) 错误:无效使用非静态数据成员 'Graph: :V' int V; //没有顶点 2)error: from this location int entry_time[V] ,exit_time[] , parent[] ;有什么办法可以在类 Graph 中定义这些大小为 V 的数组。
  • 学习使用std::vector
  • @The Dark 我使用 'new int [V]' 和 'new bool [V]' 为所有这五个变量分配了内存。这行得通。谢谢。
  • @sakshamjindal 使用std::vector——你使用new[]而不使用delete[]会造成内存泄漏。此外,使用new[] 不会对边界进行运行时检查,而可以使用std::vector::at()。在主帖中查看我的 cmets,其中包含指向使用 std::vector 的示例的链接。
  • 非常感谢您让我熟悉与 new[ ] 相关的内存泄漏。我刚刚阅读了有关向量的更多信息,并将使用它@The Dark,向量的介绍有帮助。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-01
  • 1970-01-01
  • 2020-06-28
  • 1970-01-01
  • 2020-09-30
  • 1970-01-01
  • 2018-01-22
相关资源
最近更新 更多