繁体   English   中英

如何修复 Skiena 的 dfs(深度优先搜索)实现 c++ 中的无限循环

[英]How to fix the infinite loop in Skiena's dfs (depth first search) implementation c++

即使在 Steven Skiena 第 2 版的“算法设计手册”一书中的 Skiena 的 dfs 实现中包含勘误表更改后,我也遇到了无限循环,我想知道如何解决它。 原因似乎很明显,适用于任何无向图,这让我觉得可能是我做错了,但就是想不通。

取任何无向图(或者如果你有书的话,也可以是 pg171 上的那个),比如说有一条边 (1,6)。 在邻接列表中,alist[6] 将有一个节点为 1,而 alist[1] 将有一个节点为 6。为 vertex = 1 启动 DFS(调用 dfs(1)),它首先发现 6 并设置 parent[6]= 1. 然后递归调用 dfs(6) 想要发现 1 但已经发现了 1。 这会导致 while 循环中的第一个 if 条件变为 false

if (!discovered[y]) ) 

因此不设置父[1]。

1 尚未处理,并且 parent[6] 为 1(即 y),如前一次迭代中设置的那样,因此 else if 循环中的条件也为假。

else if (((!processed[y]) && (parents[v] != y)) || (directed))

由于 else 条件为假,我们没有将指针 p 重置为链表中的下一个节点,因此它进入了无限循环

while (p != nullptr) 

所以基本上它在处理第一条边 (1,6) 和 (6,1) 时卡住了,这应该发生在任何无向图上。 这个无限循环的修复方法是什么? 或者我在这里做错了与skiena实施不同的事情?

这是重现无限循环的最小可编译和可运行代码,包括 main()

#include <iostream>
#include <queue>

const int MAX_VERTICES = 10000;
struct EdgeNode {
private:
    int y{ -1 };
    EdgeNode* next{ nullptr };
public: 
    EdgeNode(int _y,  EdgeNode* _next) : y{ _y }, next{ _next }{}
    EdgeNode(int _y) : y{ _y }, next{ nullptr}{}
    const int getY() const { return y; } ;
    const EdgeNode* const getNext() const { return next; };
    
};

class Graph {
    EdgeNode* edges[MAX_VERTICES]{ nullptr };
    int degree[MAX_VERTICES]{ 0 };
    int totalVertices{ 0 };
    int totalEdges{ 0 };    
    bool directed{ false };
    bool processed[MAX_VERTICES]{ false };
    bool discovered[MAX_VERTICES]{ false };
    bool finished = false;
    int parents[MAX_VERTICES];
    void initializeSearch() {
        for (int i = 0; i < MAX_VERTICES; i++)
        {
            parents[i] = -1;
            processed[i] = false;
            discovered[i] = false;
        }
        finished = false;
    }
public:
    int Vertices() const    {return totalVertices; }
    int Edges() const { return totalEdges; }
    const EdgeNode* getEdge(int x) const {
        if (x > MAX_VERTICES)  return nullptr;
        return edges[x];
    }
    bool insertEdge(int x, int y) { return insertEdge(x, y,  false); }
    bool insertEdge(int x, int y,  bool _directed) {
        if (x > MAX_VERTICES) { std::cout << std::endl << "Unable to insert edge. Max vertices allowed:" << MAX_VERTICES; return false; }
        EdgeNode* temp = new EdgeNode(y,  edges[x]);
        if (degree[x] == 0) totalVertices++;
        edges[x] = temp;
        degree[x]++;
        totalEdges++;
        if (!_directed) {
            insertEdge(y, x,  true);
        }
        return true;
    }
        void process_vertex_late(int vertex) {}
        void process_vertex_early(int vertex) {std::cout << std::endl << "Processing Vertex: " << vertex;}
    void process_edge_dfs(int x, int y) {       
        std::cout << std::endl << "\tProcessing Edge(" << x << "," << y << ")";
        if (discovered[y] && (parents[x] != y)) {
            std::cout << std::endl << "Cycle(" << x << "," << y << ")";
            std::cout << std::endl << std::endl;
            finished = true;
        }
    }
        void dfs1(int start) {
        initializeSearch();
        dfs(start, false);
    }
    void dfs(int v, bool print) {
        const EdgeNode* p;
        int y;
        if (finished) 
            return;
        discovered[v] = true;
        process_vertex_early(v);
        p = getEdge(v);
        while (p != nullptr) {
            y = p->getY();
            if (!discovered[y]) {
                parents[y] = v;
                process_edge_dfs(v, y);
                dfs(y, false);
            }
            else if (((!processed[y]) && (parents[v] != y)) || (directed))
            {
                process_edge_dfs(v, y);
                if (finished) 
                    return;
                p = p->getNext();
            }
        }
        process_vertex_late(v);
        processed[v] = true;
    }
    
};
int main()
{
    Graph graph;    
    graph.insertEdge(1, 2);
    graph.insertEdge(1, 5);
    graph.insertEdge(1, 6);
    graph.insertEdge(2, 5);
    graph.insertEdge(2, 3);
    graph.insertEdge(3, 4);    
    graph.insertEdge(4, 5);
    graph.dfs1(1);
    return 0;
}

我希望你能找到你的答案。

我有这本书的第二版,我明白你的错误是什么。

你写了

else if (((!processed[y]) && (parents[v] != y)) || (directed))
{
                process_edge_dfs(v, y);
                if (finished) 
                    return;
                p = p->getNext();
}

正确的实现是:

else if (((!processed[y]) && (parents[v] != y)) || (directed))
   process_edge_dfs(v, y);

if (finished) return;
p = p->getNext();
...

在我的版本中,代码分两页,alignment 不一样。 这很令人困惑。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM