遍历通用节点类,列出所有节点导致无限循环

Posted

技术标签:

【中文标题】遍历通用节点类,列出所有节点导致无限循环【英文标题】:Traversing general nodes class, listing all nodes results in a infinite loop 【发布时间】:2019-02-04 21:13:26 【问题描述】:

我正在练习遍历树/节点,我遇到了当前的问题。我希望能够将一个节点连接到自身。将节点 1 连接到节点 2。节点可以连接到任意数量的节点。这是我写和练习的当前课程。

我的问题是我无法检查我是否已经遍历了过去的节点。我得到的是一个 -> 二 -> 三 -> 四 -> 一 -> 二 ... 等等的无限循环。

是否有可能获得正确方向的提示?

我希望 nodeN.list_connections() 能够打印 nodeN 连接到的所有节点。

class Node 
private:
    std::vector<Node*> nodes;
    std::string data;
public:
    Node()
    
        printf("Status: Created [%d]\n", this);
    
    void connect(Node& node)
    
        nodes.push_back(&node);
        printf("Status: Node [%d] Connected To [%d]\n", this, &node);
    
    void input_data(std::string str_in)
    
        data = str_in;
    
    void list_connections()
    
        printf("List: Start\n");
        printf("Node[this][%d]: %s\n", this, data.c_str());
        for (size_t i = 0; i < nodes.size(); i++)
        
          printf("Node[i=%d][%d]: %s\n", i, nodes[i], nodes[i]->data.c_str());
          if (this != nodes[i])
             nodes[i]->list_connections();
        
    
;

void test_list()

    Node one;
    one.input_data("ONE");
    Node two;
    two.input_data("TWO");
    Node three;
    three.input_data("THREE");
    Node four;
    four.input_data("FOUR");

    // one -> two <-> three -> four -> one
    // one -> one
    // two -> two

    one.connect(two);
    one.connect(one);
    two.connect(two);
    two.connect(three);
    three.connect(four);
    four.connect(one);
    three.connect(two);

    one.list_connections();
    //two.list_connections();
    //three.list_connections();
    //four.list_connections();

这是我上面的代码。

我的 test_list 函数测试所有可能的连接场景。

编辑:

我的 nodeOne.list_connections() 的当前想法是,它将遍历连接到 nodeOne 的所有节点。只有当前节点未连接到其他节点时,这些节点才会使用 nodeOther.list_connections()。

编辑:

所有节点都以某种方式连接。列出连接时,它只会列出从该节点向下的连接。列出节点不会回到根/第一个节点。

编辑:

只使用一个.list_connections();输出应该是

 List: Start
 Node[this][7731340]: ONE
 Node[i=0][7731288]: TWO
 Node[i=1][7731340]: ONE
 List: Start
 Node[this][7731288]: TWO
 Node[i=0][7731288]: TWO
 Node[i=1][7731236]: THREE
 List: Start
 Node[this][7731236]: THREE
 Node[i=0][7731184]: FOUR
 Node[i=1][7731288]: TWO
 List: Start
 Node[this][7731184]: FOUR
 Node[i=0][7731340]: ONE

感谢 StephanH 指出。

【问题讨论】:

Node 中的另一个属性是boolean 怎么样。一旦你通过了一个boolean passed=true,那么下一次,如果是true,它就结束了。 如果您假设一个完全连接的图(每个节点都可以通过至少一条路径从每个其他节点到达),您可以简单地打印出图中的每个节点并打印出所有连接的节点而无需任何递归. 感谢您的回复。我确实希望连接所有节点。但是对于我要打印图中的每个节点,我需要在每个节点中携带所有节点信息,或者至少在根节点中。我不想那样做。我想打印从某个点开始的所有节点。列表节点不会上升到根目录。所以我觉得递归是我访问下一个节点的唯一方法。谢谢 M.K 我会试试的。 我更新了我的答案 【参考方案1】:

您必须解决图论中的一个常见问题(避免循环)。您可以创建一个简单的 Path 类来跟踪节点是否已经/或当前打印在当前递归堆栈中。因此,您必须检查新节点是否已经在递归堆栈中。让我们使用标准 std::find() 应用于存储节点 ID 的整数向量。为了可读性和更易于使用,我将其包装在 bool Path::closeCycle(int nid) 中。因为一条路径最多可以包含 |N| 个Path 类的元素也可以用 n 维 vector&lt;bool&gt; 表示,这将避免使用 std::find()。这可能会提高性能,但这可能取决于图的结构(长路径+少数节点与短路径+大量节点与介于与极端之间的某些东西)。

在 node.h 中

#include <cstdlib>
#include <string>
#include <vector>
#include <algorithm>


class Path

    std::vector<int> vals;
public:
    Path();
    bool closeCycle(int nid)const;
    void add(int nid);
;

class Node 
private:
    int id;
    std::vector<Node*> nodes;
    std::string data;
public:
    Node(int id) : id(id)
    
        printf("Status: Created [%d]\n", this);
    
    void connect(Node& node)
    
        nodes.push_back(&node);
        printf("Status: Node [%d] Connected To [%d]\n", this, &node);
    
    void input_data(std::string str_in)
    
        data = str_in;
    
    void list_connections(const Path& path = Path());
    inline int getId()const  return id; 
;

在 node.cpp 中

#include "header.h"

void Node::list_connections(const Path& path)

    printf("List: Start\n");
    printf("Node[this][%d]: %s\n", this, data.c_str());


    Path npath(path);
    npath.add(id);
    for (size_t i = 0; i < nodes.size(); i++)
    
        if (!npath.closeCycle(nodes[i]->id))
        
            printf("Node[i=%d][%d]: %s\n", i, nodes[i], nodes[i]->data.c_str());
            nodes[i]->list_connections(npath);
        
    
    printf("List: %s End\n", data.c_str());




Path::Path()



bool Path::closeCycle(int nid) const

    return std::find(vals.begin(), vals.end(), nid) != vals.end();


void Path::add(int nid)

    vals.push_back(nid);

你的 main.cpp

void main()

    Node one(1);
    one.input_data("ONE");
    Node two(2);
    two.input_data("TWO");
    Node three(3);
    three.input_data("THREE");
    Node four(4);
    four.input_data("FOUR");

    one.connect(two);
    one.connect(one);
    two.connect(two);
    two.connect(three);
    three.connect(four);
    four.connect(one);
    three.connect(two);

    one.list_connections();
    std::cout << "\n\n";
    two.list_connections();
    std::cout << "\n\n";
    three.list_connections();
    std::cout << "\n\n";
    four.list_connections();
    std::cout << "\n\n";

    system("pause");

【讨论】:

您好,非常感谢。我可以看到混乱。我很抱歉。但是,我想要确切的结果,只使用一个命令 one.list_connections(); 非常感谢,我想我在解决这个问题时考虑得太仔细了。我一直在尝试考虑在 list_connections 中添加越来越多的 if 语句。这听起来像是一种有趣的方式。我会尝试并添加/更改一些东西。非常感谢你。完成后,我将分享我的代码,玩弄它。 不客气。这个问题必须解决,因为它会导致堆栈溢出;)我期待您的改进版本

以上是关于遍历通用节点类,列出所有节点导致无限循环的主要内容,如果未能解决你的问题,请参考以下文章

mysql如何无限极查找最顶层id节点

react 实现一个无限循环的轮播器 附github地址

打破节点repl中的无限循环?

PHP 循环删除无限分类子节点

无限循环的原因? (迭代中序遍历实现)C++

双向链表无限循环? [关闭]