微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

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

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

if (!discovered[y]) ) 

因此不会设置 parent[1]。

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

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

由于 else 条件 a 为假,我们没有将指针 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();
...

在我的版本中,代码在两页上,对齐方式不一样。 这很令人困惑。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。