在多对多关系中查找两个不相关对象的最快方法以及C ++中的实现

时间:2019-03-16 17:53:20

标签: c++ algorithm data-structures many-to-many relationship

基本设置是,假设我们有两个简单的类:

class User {
     private:
        int id;
     public:
        User(int id){ this->id = id };
};

class Channel {
     private:
        std::string name;
     public:
        Channel(std::string name) { this->name = name };
};

这两个类应该相互之间存在多对多关系,例如每个User可以加入许多Channel,每个Channel可以拥有许多User

Channel个对象的数量-数百个。 User个对象的数量-数万个。

任务制定::给定一个特定的Channel对象,我必须找到一个与它无关User

问题:

1)考虑到给定的任务,这种多对多关系的最佳实现是什么?除了针对所有关系的直接迭代之外,是否有针对这种问题的特定算法?

2)如果关系应该具有一些其他属性,例如是否存储User加入Channel的时间?

我的想法:第一个想法是创建一些其他类,例如

class UserChannelRel {
    private:
        User* userPtr;
        Channel* chPtr;
        float timeJoined;
    public:
        UserChannelRel(User* user, Channel* channel, float tm) {
             this->userPtr = user;
             this->chPtr = channel;
             this->timeJoined = tm;
        }
};

并将它们存储在某个大的标准容器中(向量?)。但是然后遍历所有元素似乎很慢。

2 个答案:

答案 0 :(得分:4)

首先,您可以创建两个存储库,以在一侧保留用户的完整列表,在另一侧保留频道的完整列表。通常,您可以使用maps

map<int, User> users;
map<std::string, Channel> channels;  

然后,我建议为每个频道吸引set个用户:

class Channel {
     private:
        std::string name;
        std::set<int> subscribers; 
     public:
        Channel(std::string name):name(name) { };
        void add(int userid) {
            subscribers.insert(userid);
        }
};

然后要查找与某个频道无关的用户,您可以遍历这些用户并轻松检查该频道中是否包含该用户。

或者,您也可以使用全局用户集(或者与存储库同时维护集成员身份,或者由creating the set from the map来维护),并使用set_difference()生成不属于用户的用户集。订阅者。

Example of use of set_difference

set<int> a { 1,2,3,4,5,6,7};   // imagine a set of all the users
set<int> b{ 2,3,8};            // imagine a set of the subscribers of a channel
vector<int> c;                 // container with the users who are not subscribers

set_difference(a.begin(),a.end(), b.begin(), b.end(), back_inserter(c)); 
copy(c.begin(), c.end(), ostream_iterator<int>(cout," "));

如何在两种方法之间进行选择?第一种方法(迭代和检查)具有快速找到第一个用户并开始对提案进行处理的优势。通过利用对集合和映射进行排序的事实,可以优化迭代。您无需查找所有用户。第二种方法很优雅,但是由于用户群庞大,可能需要花费更多时间,因为在执行任何操作之前都需要获得完整的结果。

答案 1 :(得分:0)

也许您可以尝试使用std::shared_ptr

每个User到它们加入的shared_ptr会有一组Channels,这可以节省内存,因为一个Channel可以由多个用户加入。

您可以执行同样的操作将Users存储在Channels中。

然后,您可以将Users放在vector中,并使用某种排序方式(例如合并等高效方式,尝试对现有的现有排序方式进行基准测试),以查看{{ 1}}的指针指向您正在查看的User