我有一个类似于:
的文本文件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;
};
答案 0 :(得分:1)
您的数据样本有几个问题仍未得到解答:是否只有一个单一的入口点(例如:人)?它总是自上而下分解(即每个元素最多有一个父元素)?这些元素总是来自正确的odrer:首先是顶部,然后是向下?
如果所有三个问题的答案都是肯定的,那么您建议的结构是合适的:
还有几点需要解决:
如您所见,最佳数据结构不仅取决于内容,还取决于您将如何使用它。
有很多其他方法可以做到这一点,以不同的方式平衡性能方面。例如:
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。
答案 1 :(得分:0)
每个“单词”都需要自己的节点。所以,你的第二个结构更接近。但是,只要确保子节点的容器类型在创建节点后可以动态增长,并包含指向子节点的指针。
有两个原因:
(1)假设我们在您的数据底部添加了一行:arm: wrist
。在创建了arm节点之后,需要将它附加到子项上
(2)目前,您的数据文件排序良好。但是,如果我们随机化您的数据行的顺序怎么办?那还能用吗?大多数有向图程序都处理得很好
当你从左到右解析一行时,得到这个词。搜索所有已知节点,查找匹配项。在解析第一行之后,您有三个节点:person,head,body。头部和身体都在人的子女中[他们的parent
字段都指向人],但他们的子列表[当前]是空的。 person将是root
节点。
如果找到匹配项,您将在第二行上找到匹配项,请使用现有的头节点,并填写子项。如果没有匹配项,请创建节点。
如果搜索失败并且您必须创建一个新节点,那么您构建的树中可能没有一个位置可以将其附加到该节点。在这种情况下,将其添加到“保留”列表[也是搜索的一部分],直到有更多节点进入并且您可以将保留项目作为子项附加,在这种情况下,您将其从保留列表中删除。
您可能必须更新root
节点。使用示例数据,假设我们在底部添加了household: person dog
。 root
节点需要相应调整。我们还需要dog:
行。如果我们最后没有它,那就是 undefined 值,需要标记。您的节点定义需要defined
bool才能标记此内容。
最后,保留列表中的任何内容都是无关数据。例如,如果我们有一个zebra:
行,则没有对它的引用[并且它的parent
将为null],并且还需要标记该行。
当链接内容时,给定节点只能引用一次。所以,如果我们添加household: arm
,这将会发生冲突,因为手臂已经是身体的一个孩子。通过parent
已经非空