C++ C++;多对多地图
我需要一个数据结构来存储这些信息,以便:(我有多对多) 1.如果有员工,我可以找到项目 2.考虑到项目,我可以找到员工 如果我使用多地图,那么我需要维护2张地图,C++ C++;多对多地图,c++,C++,我需要一个数据结构来存储这些信息,以便:(我有多对多) 1.如果有员工,我可以找到项目 2.考虑到项目,我可以找到员工 如果我使用多地图,那么我需要维护2张地图, 这里还有其他数据结构可以使用吗 > P>你可以使用两个映射,也可以使用.< /P> < P>我不知道在标准C++中有任何预先打包的数据结构。在我看来,您需要两种数据结构,其形式如下: std::map<unsigned long,std::vector<unsigned long> > employee_pro
这里还有其他数据结构可以使用吗 > P>你可以使用两个映射,也可以使用.< /P> < P>我不知道在标准C++中有任何预先打包的数据结构。在我看来,您需要两种数据结构,其形式如下:
std::map<unsigned long,std::vector<unsigned long> > employee_projects
std::映射员工项目
其中一个是:
std::map<unsigned long,std::vector<unsigned long> > project_employees
std::映射项目员工
其中employee_projects是映射到projectd列表的整数(employeeid)列表,而project_employees则是相反的。预先填充这两个,您可以在整个应用程序中快速引用它们
警告:运行期间的任何修改都必须手动应用于每个结构。选择您认为最常见的关系并创建映射。然后,编写函数或从map类派生,并使用方法进行扩展,以便在另一个方向执行查找。这种查找显然要慢得多(必须迭代这些值),但它可以让您只使用一个映射
如果你意识到你需要更多地查找另一个地图,或者你想切换到使用2个地图或其他解决方案,那么最好将整个事情包装在一个类中,这样你就可以更改地图。你可以按照你的建议使用两个大的全局ish多重地图,也可以在项目和员工数据结构中本地维护信息。让Project类包含指向Employee的指针向量(或集合),Employee类包含指向Project的指针向量/集合,以及一个函数,该函数通过将指向每个员工的指针推到另一个员工的向量上,将员工与项目相关联。然后,给定其中一个对象,可以获得与之关联的其他类型的对象的集合。比如:
(in Employee.h):
class Project; // Forward declare project
class Employee {
public:
AddProject(Project *proj);
vector<Project *> projects();
size_t num_projects() {return projects_.size();}
Project *project(size_t i) {return projects_[i];}
private:
vector<Project *> projects_;
};
(在Employee.h中):
类项目;//远期申报项目
班级员工{
公众:
添加项目(项目*项目);
向量项目();
size_t num_projects(){return projects.size();}
项目*项目(大小){返回项目}
私人:
矢量工程;
};
同样的,对于Project.h
任何一种方法都可以奏效;本地方法是在没有可用的multimap的语言(如C)中通常采用的方法。您还可以使用索引或ID代替指针。本地方法的一个优点是,您需要对项目和员工进行的更多工作可以成为项目/员工类的本地行为,使用这些类的方法实现,并与系统的其余部分分开进行单元测试。这不适用于多重映射方法,因为单个类对多重映射一无所知
这里的区别不是很明显,这里只有两个类,但我见过很多这样的关系用大型全局ish数据结构表示,这些数据结构是大型monster类的一部分,单元测试几乎不可能(因为您需要在monster类中设置如此多的数据结构才能完成任何事情)。您可以使用
您可以按如下方式定义容器:
struct Connection
{
Employee emp;
Project prj;
};
typedef multi_index_container
<
Connection,
indexed_by
<
ordered_unique< identity<Connection> >,
ordered_non_unique< member<Connection, Employee, &Connection::emp> >,
ordered_non_unique< member<Connection, Project, &Connection::prj> >
>
> Relation;
+1,我想说在一个新类上包装两个映射,但是Bimap已经解决了这个问题,很好的发现。但是这不允许多对多关系,是吗?在我看来,在Bimap中,键必须是唯一的,两边都是,这样只能处理一对一的关系。(很抱歉挖出来了…)
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/member.hpp>
#include <iostream>
#include <string>
#include <functional>
namespace mi = boost::multi_index;
// these two type should implement std::less or operator<
typedef std::string Employee; // change to your definition
typedef std::string Project; // change to your definition
struct Connection
{
Employee emp;
Project prj;
Connection(const Employee& e, const Project& p): emp(e), prj(p) {}
bool operator <(const Connection& rhs) const
{
return std::less<Employee>()(emp, rhs.emp) ||
( emp == rhs.emp && std::less<Project>()(prj, rhs.prj) );
}
};
struct employee {}; // for tag
struct project {}; // for tag
typedef mi::multi_index_container
<
Connection,
mi::indexed_by
<
mi::ordered_unique
<
mi::identity<Connection>
>,
mi::ordered_non_unique
<
mi::tag<employee>,
mi::member<Connection, Employee, &Connection::emp>
>,
mi::ordered_non_unique
<
mi::tag<project>,
mi::member<Connection, Project, &Connection::prj>
>
>
> Relation;
typedef Relation::index_iterator<employee>::type EmpIter;
typedef Relation::index_iterator<project>::type PrjIter;
int main()
{
Relation rel;
rel.insert(Connection("Tom", "sleeping"));
rel.insert(Connection("Jerry", "sleeping"));
rel.insert(Connection("Spike", "sleeping"));
rel.insert(Connection("Tom", "tormenting-partner"));
rel.insert(Connection("Jerry", "tormenting-partner"));
rel.insert(Connection("Spike", "playing-with-tyke"));
rel.insert(Connection("Tom", "fishing"));
rel.insert(Connection("Jerry", "playing-with-nibbles"));
rel.insert(Connection("Jerry", "tormenting-partner")); // duplicated
std::cout << "total connections: " << rel.size() << std::endl;
std::cout << "employees connected with sleeping project:" << std::endl;
std::pair<PrjIter, PrjIter> pit = rel.get<project>().equal_range("sleeping");
for (PrjIter it = pit.first; it != pit.second; ++it)
std::cout << '\t' << it->emp << std::endl;
std::cout << "projects connected with Jerry:" << std::endl;
std::pair<EmpIter, EmpIter> eit = rel.get<employee>().equal_range("Jerry");
for (EmpIter it = eit.first; it != eit.second; ++it)
std::cout << '\t' << it->prj << std::endl;
return 0;
}
total connections: 8
employees connected with sleeping project:
Tom
Jerry
Spike
projects connected with Jerry:
sleeping
tormenting-partner
playing-with-nibbles