第二次在图上运行时,广度/深度优先搜索导致崩溃

Posted

技术标签:

【中文标题】第二次在图上运行时,广度/深度优先搜索导致崩溃【英文标题】:Breadth / Depth First Search causes crash when run on graph for second time 【发布时间】:2019-12-04 10:53:55 【问题描述】:

所以我有一个已添加顶点和边的有向图。该图表示机场和它们之间的航班。当我运行广度优先或深度优先搜索以查找两个机场之间的路径时,我第一次得到正确答案,但是当我第二次使用完全相同的机场运行它时,它找不到路径并且程序崩溃错误代码-1073741819。几个小时以来,我一直试图弄清楚这一点,但我很困惑。 我运行了调试器,当 BFS 算法进入图形的 IsMarked() 函数时,问题似乎出现了。它无法读取 vertices[] 数组并且调试器说

这是我的图表类

#pragma once
#include "queue.h"
const int NULL_EDGE = 0;

template<class VertexType>
class GraphType

public:
    GraphType();            // constructor, default of 50 vertices.
    GraphType(int maxV);    // parameterized constructor, maxV <= 50.
    ~GraphType();           // destructor    

    void MakeEmpty();
    bool IsEmpty() const;
    bool IsFull() const;
    void AddVertex(VertexType);
    void AddEdge(VertexType, VertexType, int);
    int WeightIs(VertexType, VertexType);//             (fromVertex, toVertex).
    void GetToVertices(VertexType, QueType<VertexType>&);   
    void ClearMarks();
    void MarkVertex(VertexType);
    bool IsMarked(VertexType) const;
    void DisplayFlights();


private:
    int numVertices;
    int maxVertices;
    VertexType* vertices;
    int edges[50][50];
    bool* marks; // marks[i] is mark for vertices[i].


;


template<class VertexType>
GraphType<VertexType>::GraphType()
// Post: Arrays of size 50 are dynamically allocated for
//       marks and vertices. numVertices is set to 0;
//       maxVertices is set to 50.

    numVertices = 0;
    maxVertices = 50;
    vertices = new VertexType[50];
    marks = new bool[50];
    //ClearMarks();


template<class VertexType>
GraphType<VertexType>::GraphType(int maxV)
// Post: Arrays of size maxV are dynamically
// allocated for marks and vertices.
// numVertices is set to 0; maxVertices is set to maxV.

    numVertices = 0;
    maxVertices = maxV;
    vertices = new VertexType[maxV];
    marks = new bool[maxV];
    //ClearMarks();


template<class VertexType>
GraphType<VertexType>::~GraphType()
// Post: arrays for vertices and marks have been   // deallocated.

    delete[] vertices;
    delete[] marks;


template<class VertexType>
void GraphType<VertexType>::MakeEmpty()

   //not yet coded



template<class VertexType>
bool GraphType<VertexType>::IsEmpty() const

    return (numVertices == 0);


template<class VertexType>
bool GraphType<VertexType>::IsFull() const

    return (numVertices == maxVertices);


template<class VertexType>
void GraphType<VertexType>::AddVertex(VertexType vertex)
// Post: vertex has been stored in vertices.
//       Corresponding row and column of edges have been
//    set to NULL_EDGE.
//       numVertices has been incremented.

    //Not allowed to add duplicate vertex
    bool duplicate = false;
    for (int i = 0; i < numVertices; i++) 
        if (vertices[i] == vertex)
            duplicate = true;
    

    if (!duplicate) 
        vertices[numVertices] = vertex;
        for (int index = 0; index < numVertices; index++)
        
            edges[numVertices][index] = NULL_EDGE;
            edges[index][numVertices] = NULL_EDGE;
        
        numVertices++;
    
    else 
        cerr << "Cannot add duplicate vertex\n";
    



template<class VertexType>
int IndexIs(VertexType * vertices,VertexType vertex)
    // Post: Function value = index of vertex in vertices.

    int index = 0;
    while (!(vertex == vertices[index]))
        index++;
    return index;


template<class VertexType>
void GraphType<VertexType>::AddEdge(VertexType fromVertex,VertexType toVertex, int weight)
    // Post: Edge (fromVertex, toVertex) is stored in edges.

    /*int row;
    int column;*/
    int row = IndexIs(vertices, fromVertex);
    int col = IndexIs(vertices, toVertex);
    edges[row][col] = weight;


template<class VertexType>
int GraphType<VertexType>::WeightIs(VertexType fromVertex,VertexType toVertex)
    // Post: Function value = weight associated with the
    //      edge (fromVertex, toVertex).

    /*int row;
    int column;*/
    int row = IndexIs(vertices, fromVertex);
    int col = IndexIs(vertices, toVertex);
    return edges[row][col];


template<class VertexType>
void GraphType<VertexType>::GetToVertices(VertexType vertex, QueType<VertexType>& adjvertexQ)

    int fromIndex;
    int toIndex;

    fromIndex = IndexIs(vertices, vertex);
    for (toIndex = 0; toIndex < numVertices; toIndex++)
        if (edges[fromIndex][toIndex] != NULL_EDGE)
            adjvertexQ.Enqueue(vertices[toIndex]);


template<class VertexType>
void GraphType<VertexType>::ClearMarks()

    for (int i = 0; i < maxVertices; i++) 
        marks[i] = false;
    


template<class VertexType>
void GraphType<VertexType>::MarkVertex(VertexType vertex)

    for (int i = 0; i < numVertices; i++) 
        if (vertex == vertices[i]) 
            marks[i] = true;
            break;
        
    

    /*int index = 0;
    while (!(vertex == vertices[index])) 
        if (vertex == vertices[index]) 
            marks[index] = true;
            index++;
        

    */



template<class VertexType>
bool GraphType<VertexType>::IsMarked(VertexType vertex) const


    for (int i = 0; i < numVertices; i++) 
        if (vertices[i] == vertex) 
            return marks[i];
        
    


template<class VertexType>
void GraphType<VertexType>::DisplayFlights()

    //foreach vertex
    QueType<VertexType> q;
    VertexType adjVertex;
    int weight;
    for (int i = 0; i < numVertices; i++) 
        GetToVertices(vertices[i], q);
        //get adjacent vertices
        while (!q.IsEmpty()) 
            q.Dequeue(adjVertex);
            weight = WeightIs(vertices[i], adjVertex);
            cout << vertices[i] << " to " << adjVertex << " " << weight << endl;
        
    





我的广度优先搜索

void BreadthFirstSearch(GraphType<string> graph, string startVertex, string endVertex)
    // Assumes VertexType is a type for which the “==“ and “<<“
    // operators are defined.

    QueType<string> queue;
    QueType<string> vertexQ;
    bool found = false;
    string vertex;
    string item;
    graph.ClearMarks();
    queue.Enqueue(startVertex);
    do
    
        queue.Dequeue(vertex);
        if (vertex == endVertex)
        
            cout << vertex;
            found = true;
        
        else
        
            if (!graph.IsMarked(vertex))
            
                graph.MarkVertex(vertex);
                cout << vertex << " ";
                graph.GetToVertices(vertex, vertexQ);
                while (!vertexQ.IsEmpty())
                
                    vertexQ.Dequeue(item);
                    if (!graph.IsMarked(item))
                        queue.Enqueue(item);
                
            
        
     while (!queue.IsEmpty() && !found);
    if (!found)
        cout << "Path not found." << endl;

非常感谢任何帮助。非常感谢。

【问题讨论】:

您好,欢迎来到 ***。您应该将 BFS 中涉及的Graph 方法添加到您的问题中,例如GetToVerticesMarkIsMarked 等,以便读者看到大部分涉及的代码。编写出错时输出的错误消息也会很有帮助。 如果你能创建一个Minimal Reproducible Example 会很有帮助。现在,我想,它与复制指针有关。当您将 BreadthFirstSearch 更改为 void BreadthFirstSearch(GraphType&lt;string&gt; &amp;graph, string startVertex, string endVertex)(按引用传递)时,是否也会出现此错误? @churill 是的,将图表更改为通过引用传递似乎已经解决了问题。 【参考方案1】:

void BreadthFirstSearch(GraphType&lt;string&gt; graph, string startVertex, string endVertex) 中,您通过值传递GraphType&lt;string&gt;,这意味着创建了一个临时副本。那里的指针 verticesmarks 也被复制,但不是它们指向的值

所以原始对象和临时对象都有指向相同内存位置的指针。 在BreadthFirstSearch 结束时,临时对象被销毁。在析构函数中,你 delete[] verticesmarks

现在原始对象中的指针指向已释放的内存,这会导致未定义的行为。 最简单的解决方案是通过引用传递GraphType&lt;string&gt;

void BreadthFirstSearch(GraphType<string> &graph, string startVertex, string endVertex)

但为了安全起见,强烈建议使用std::vector,而不是手动管理内存。

【讨论】:

【参考方案2】:

问题是,一旦你执行了你的算法,一旦图形以大量标记的顶点结束。您需要清除标记以进行第二次执行。

【讨论】:

以上是关于第二次在图上运行时,广度/深度优先搜索导致崩溃的主要内容,如果未能解决你的问题,请参考以下文章

算法-03 | 深度优先DFS| 广度优先BFS

算法之深度和广度优先搜索算法

十深度优先 && 广度优先

我们能否以将 DFS 应用于新图将导致与在第一个图上应用 BFS 相同的遍历顺序的方式转换图?

图解:深度优先搜索与广度优先搜索

深度优先搜索和广度优先搜索、A星算法三种算法的区别和联系?