用于存储两组唯一元素之间的多种关系的 C++ 数据结构
C++ data structure to store multiple relationships between two unique sets of elements
我正在从事一个项目,其中有两组独特的元素。一组中的任何元素都可能与另一组中的任何元素相关。
示例:
第 1 组:{A、B、C}
第 2 组:{1, 2, 3, 4}
允许的关系:
(A, 1) (A, 3)
(B, 1) (B, 4)
(C, 1) (C, 3) (C, 4)
单个关系表示为一对括号内的两个集合元素。
在我的特定项目中,两个集合的元素都是对象,我希望存储的所有对象的所有引用都解析为一个对象(例如,包含 A 的所有关系都将引用同一个对象 A,关系另一端对其他集合的引用也是如此。
我正在考虑使用 Boost bimap
来解决这个问题。我正在研究用于 bimap 左右两半的集合的潜在类型以及这两个集合之间的关系,并一直在尝试确定哪些是正确的。
对于 bimap
的左半部分和右半部分,我认为 set_of
CollectionType
是正确的,因为我的两组对象是,嗯,集合,而且我不想在我的 bimap
中复制任何元素。
然而,当我在实践中尝试这个时,我最终无法在插入关系 (A, 1) 之后插入关系 (B, 1),因为插入必须是在左视图和右视图中都有效,以便它发生。为了纠正这个问题,我将两半的 CollectionType
更改为 multiset_of
。所有值都已正确插入,但是,这是否意味着我的 bimap
现在具有原始集合元素的副本?
为了尝试纠正这个问题,我开始考虑更改 bimap
两半之间关系的集合类型。由于关系类型的集合类型默认为bimap
的左半部分,我认为multiset_of
不正确,指定为set_of
。但是,我不确定这是否解决了我原来的问题,即我的原始集合中有多个对象副本。
我真正需要的是查看第 2 组中与第 1 组中的某个元素相关的所有对象。Boost bimap
对我来说是正确的路线吗?我选择的集合和关系类型是否正确?顺便说一句,我正在尝试自定义我的地图以具有快速搜索时间,而不用担心插入时间(删除和修改永远不会发生,地图已初始化,然后仅用于查找)。我应该只写一个自定义数据结构吗?
这让我觉得更多的是图形问题,最好更直接地建模:
struct nodeB;
struct nodeA {
char label;
std::vector<nodeB *> assocs;
};
struct nodeB {
int label;
std::vector<nodeA *> assocs;
};
从那里,我猜你想要一个 class 来管理每种类型的集合,并处理添加节点以确保你的不变量得到正确维护。
我完全同意杰瑞的回答。例如,如果您尝试对图形建模,请考虑使用邻接列表、边列表或矩阵表示。
Paul 的回答有点含糊,所以,这里有一个使用 Boost Multi Index 的示例:
#include <iostream>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/ordered_index.hpp>
struct T1 {
std::string name;
bool operator<(T1 const& o) const { return name < o.name; }
};
struct T2 {
int id;
bool operator<(T2 const& o) const { return id < o.id; }
};
namespace bmi = boost::multi_index;
struct Relation {
T1 const* key1;
T2 const* key2;
std::string const& name() const { return key1->name; }
int id () const { return key2->id; }
friend std::ostream& operator<<(std::ostream& os, Relation const& r) {
return os << "(" << r.name() << ", " << r.id() << ")";
}
};
using RelationTable = bmi::multi_index_container<Relation,
bmi::indexed_by<
bmi::ordered_unique<bmi::tag<struct by_composite>,
bmi::composite_key<Relation,
bmi::const_mem_fun<Relation, std::string const&, &Relation::name>,
bmi::const_mem_fun<Relation, int, &Relation::id>
>
>
> >;
#include <set>
int main() {
using namespace std;
set<T1> set1 { {"A"}, {"B"}, {"C"} };
set<T2> set2 { {1}, {2}, {3}, {4} };
// convenient data entry helpers
auto lookup1 = [&set1](auto key) { return &*set1.find(T1{key}); }; // TODO error check?
auto lookup2 = [&set2](auto key) { return &*set2.find(T2{key}); };
auto relate = [=](auto name, auto id) { return Relation { lookup1(name), lookup2(id) }; };
// end helpers
RelationTable relations {
relate("A", 1), relate("A", 3),
relate("B", 1), relate("B", 4),
relate("C", 1), relate("C", 3), relate("C", 4),
};
for (auto& rel : relations)
std::cout << rel << " ";
}
版画
(A, 1) (A, 3) (B, 1) (B, 4) (C, 1) (C, 3) (C, 4)
我正在从事一个项目,其中有两组独特的元素。一组中的任何元素都可能与另一组中的任何元素相关。
示例:
第 1 组:{A、B、C}
第 2 组:{1, 2, 3, 4}
允许的关系:
(A, 1) (A, 3)
(B, 1) (B, 4)
(C, 1) (C, 3) (C, 4)
单个关系表示为一对括号内的两个集合元素。
在我的特定项目中,两个集合的元素都是对象,我希望存储的所有对象的所有引用都解析为一个对象(例如,包含 A 的所有关系都将引用同一个对象 A,关系另一端对其他集合的引用也是如此。
我正在考虑使用 Boost bimap
来解决这个问题。我正在研究用于 bimap 左右两半的集合的潜在类型以及这两个集合之间的关系,并一直在尝试确定哪些是正确的。
对于 bimap
的左半部分和右半部分,我认为 set_of
CollectionType
是正确的,因为我的两组对象是,嗯,集合,而且我不想在我的 bimap
中复制任何元素。
然而,当我在实践中尝试这个时,我最终无法在插入关系 (A, 1) 之后插入关系 (B, 1),因为插入必须是在左视图和右视图中都有效,以便它发生。为了纠正这个问题,我将两半的 CollectionType
更改为 multiset_of
。所有值都已正确插入,但是,这是否意味着我的 bimap
现在具有原始集合元素的副本?
为了尝试纠正这个问题,我开始考虑更改 bimap
两半之间关系的集合类型。由于关系类型的集合类型默认为bimap
的左半部分,我认为multiset_of
不正确,指定为set_of
。但是,我不确定这是否解决了我原来的问题,即我的原始集合中有多个对象副本。
我真正需要的是查看第 2 组中与第 1 组中的某个元素相关的所有对象。Boost bimap
对我来说是正确的路线吗?我选择的集合和关系类型是否正确?顺便说一句,我正在尝试自定义我的地图以具有快速搜索时间,而不用担心插入时间(删除和修改永远不会发生,地图已初始化,然后仅用于查找)。我应该只写一个自定义数据结构吗?
这让我觉得更多的是图形问题,最好更直接地建模:
struct nodeB;
struct nodeA {
char label;
std::vector<nodeB *> assocs;
};
struct nodeB {
int label;
std::vector<nodeA *> assocs;
};
从那里,我猜你想要一个 class 来管理每种类型的集合,并处理添加节点以确保你的不变量得到正确维护。
我完全同意杰瑞的回答。例如,如果您尝试对图形建模,请考虑使用邻接列表、边列表或矩阵表示。
Paul 的回答有点含糊,所以,这里有一个使用 Boost Multi Index 的示例:
#include <iostream>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/ordered_index.hpp>
struct T1 {
std::string name;
bool operator<(T1 const& o) const { return name < o.name; }
};
struct T2 {
int id;
bool operator<(T2 const& o) const { return id < o.id; }
};
namespace bmi = boost::multi_index;
struct Relation {
T1 const* key1;
T2 const* key2;
std::string const& name() const { return key1->name; }
int id () const { return key2->id; }
friend std::ostream& operator<<(std::ostream& os, Relation const& r) {
return os << "(" << r.name() << ", " << r.id() << ")";
}
};
using RelationTable = bmi::multi_index_container<Relation,
bmi::indexed_by<
bmi::ordered_unique<bmi::tag<struct by_composite>,
bmi::composite_key<Relation,
bmi::const_mem_fun<Relation, std::string const&, &Relation::name>,
bmi::const_mem_fun<Relation, int, &Relation::id>
>
>
> >;
#include <set>
int main() {
using namespace std;
set<T1> set1 { {"A"}, {"B"}, {"C"} };
set<T2> set2 { {1}, {2}, {3}, {4} };
// convenient data entry helpers
auto lookup1 = [&set1](auto key) { return &*set1.find(T1{key}); }; // TODO error check?
auto lookup2 = [&set2](auto key) { return &*set2.find(T2{key}); };
auto relate = [=](auto name, auto id) { return Relation { lookup1(name), lookup2(id) }; };
// end helpers
RelationTable relations {
relate("A", 1), relate("A", 3),
relate("B", 1), relate("B", 4),
relate("C", 1), relate("C", 3), relate("C", 4),
};
for (auto& rel : relations)
std::cout << rel << " ";
}
版画
(A, 1) (A, 3) (B, 1) (B, 4) (C, 1) (C, 3) (C, 4)