将文本文件解析为C ++有向图或邻接列表?

时间:2015-11-03 20:37:51

标签: c++ data-structures graph

我有一个类似于:

的文本文件
person: head, body
head: eyes, nose, ears, mouth
body: arm, leg
arm: elbow, hand
leg: thigh, knee, foot

我试图在邻接列表或有向图中表示这一点。最好的方法是什么?我无法弄清楚最好的数据结构或如何用C ++表示。

我尝试过使用一个带有键值(人物,头部等)和它的父索引的结构,以及它的子项作为向量:

struct Node
{
    string key;
    int parentIndex;
    vector<string> children;
};

但这似乎并不高效。有什么想法吗?

也许这会更好?

struct {
    string key;
    Node* parent;
    vector<Node> children;
};

2 个答案:

答案 0 :(得分:1)

您的数据样本有几个问题仍未得到解答:是否只有一个单一的入口点(例如:人)?它总是自上而下分解(即每个元素最多有一个父元素)?这些元素总是来自正确的odrer:首先是顶部,然后是向下?

如果所有三个问题的答案都是肯定的,那么您建议的结构是合适的:

  • 如果总是从顶部开始探索,那就足够了。
  • 找到特定节点会很费时,因为您要遍历整个结构。

还有几点需要解决:

  • 复制节点会很棘手(因为指向父节点的指针必须针对复制的节点以及它的孩子和孩子的孩子进行更改。
  • 向数组添加元素可能会使所有chilren和children的子项的父poitner无效。

如您所见,最佳数据结构不仅取决于内容,还取决于您将如何使用它。

有很多其他方法可以做到这一点,以不同的方式平衡性能方面。例如:

class mygraph {
    struct node {  // nodes that you read:  
       string name;  
       int id;            // index of the node in the nodes vector
       vector<int> in;    // parent(s) that can lead to this node
       vector<int> out;   // children you can go to
    };
    vector<node> nodes;    // all the nodes in arbitrary sequential order  
    map<string, int> dict; // map converting the names into ids (redundant and optional, useful for efficien search by name); 
public: 
    // members to populate the structure and to acces the nodes cleanly.   
};

优点:

  • 通过id查找任何节点非常快,因为它只是索引数组。
  • 你不需要担心结构的副本,因为没有指针。
  • 由于输入/输出向量,您可以从您想要的任何节点快速向前或向后移动。
  • 冗余映射(即索引和名称)按名称加速搜索节点

不便:填充结构时会有一些开销:您需要通过验证地图中的名称将每个名称转换为id,如果不存在,则在节点向量中创建一个新节点,并在地图中插入名称+新ID。

答案 1 :(得分:0)

每个“单词”都需要自己的节点。所以,你的第二个结构更接近。但是,只要确保子节点的容器类型在创建节点后可以动态增长,并包含指向子节点的指针。

有两个原因:
(1)假设我们在您的数据底部添加了一行:arm: wrist。在创建了arm节点之后,需要将它附加到子项上 (2)目前,您的数据文件排序良好。但是,如果我们随机化您的数据行的顺序怎么办?那还能用吗?大多数有向图程序都处理得很好

当你从左到右解析一行时,得到这个词。搜索所有已知节点,查找匹配项。在解析第一行之后,您有三个节点:person,head,body。头部和身体都在人的子女中[他们的parent字段都指向人],但他们的子列表[当前]是空的。 person将是root节点。

如果找到匹配项,您将在第二行上找到匹配项,请使用现有的头节点,并填写子项。如果没有匹配项,请创建节点。

如果搜索失败并且您必须创建一个新节点,那么您构建的树中可能没有一个位置可以将其附加到该节点。在这种情况下,将其添加到“保留”列表[也是搜索的一部分],直到有更多节点进入并且您可以将保留项目作为子项附加,在这种情况下,您将其从保留列表中删除。

您可能必须更新root节点。使用示例数据,假设我们在底部添加了household: person dogroot节点需要相应调整。我们还需要dog:行。如果我们最后没有它,那就是 undefined 值,需要标记。您的节点定义需要defined bool才能标记此内容。

最后,保留列表中的任何内容都是无关数据。例如,如果我们有一个zebra:行,则没有对它的引用[并且它的parent将为null],并且还需要标记该行。

当链接内容时,给定节点只能引用一次。所以,如果我们添加household: arm,这将会发生冲突,因为手臂已经是身体的一个孩子。通过parent已经非空

来检测此项