在我的朋友网络中找到最受欢迎的喜欢

时间:2012-09-17 09:30:24

标签: c++ algorithm stl popularity top-n

我正在寻找一种在朋友网络中找到最受欢迎的喜欢的方法。 “我朋友网络中最受欢迎的”被定义为“拥有我朋友最多的喜欢”。

假设每个朋友都有一个唯一的ID,并且有许多喜欢的页面。所以,考虑到一群这样的朋友,我想找到最喜欢的朋友喜欢的喜欢,喜欢这个东西的朋友。从本质上讲,我想展示一些类似“你的朋友X,Y& Z喜欢这个。”

我的第一个解决方案是使用Map(用于存储反向映射:like-> set)和Priority Queue(用于查找前N个)。这是我的算法(使用C ++ STL):

map< like, set<friend> > like2friendsMap;
for each friend {
  for each like {
    like2friendsMap[like].insert(friend); //populate the map
  }
}

priority_queue< pair<like, int> > pq;
for each like in like2friendsMap {
  int count = like2friendsMap[like].size(); //no. of friends who like this or "popularity"
  pq.push(like, count); //count is the priority
}

map< like, set<friend> > result
for i in 1 to N { //N is how many popular items I want
   result = pq.top();  //gives me the element with highest priority (most popular like)
   pq.pop();
}

由于STL内部使用红黑树实现优先级队列的映射和最小/最大堆,这种方法对我来说似乎相当快。但如果我有100个朋友,每个人都有100个喜欢,那么内存使用量就会很大。当然,我不应该存储整个对象,而应该使用friend id和id来进行所有计算,这会大大减少内存使用量。

可以使用哪种其他算法或数据结构来提高效率(提高速度,减少内存)?出于某种原因,我无法存储每个朋友的列表,它必须在运行时计算。我正在使用C ++开发它,因此使用STL或boost的解决方案会更好。

3 个答案:

答案 0 :(得分:1)

create an integer list allPages which can be referenced by page
initialize it with 0
for every friend f
{
    for every page p liked by f
    {
        allPages[p]++;
    }
}
get the maximum of the allPages[p]

如果P是页数,则其空间复杂度为O(P)

如果F是朋友的数量,L是每个人都喜欢的平均页数。然后它的时间复杂度为O(F*L)。所以即使你再次遍历所有的朋友来检查谁都喜欢这个页面,这也不会增加复杂性。

O(F*L) + O(F) would remain O(F*L)

我认为最好再次迭代而不是存储朋友。

或者您可以为页面存储反向引用。这是针对每个页面,存储喜欢的朋友列表。这不会占用太多空间,并且能够以最低的复杂性完成工作。

答案 1 :(得分:0)

我无法理解您使用priority_queue的原因。当然,它有效地跟踪容器被更改时的最大元素。但是在第一步之后你只需要单次操作。总结:

priority_queue< pair<like, int> > pq;
std::priority_queue< pair<like, int> >::const_iterator max_friends = pq.begin()
for(i = like2friendsMap.begin() to .end())  {
  if (max_friends->size() < i->size()) max_friends = i;
}

当然这只适用于N = 1,但这足以让你的朋友X,Y和Z像这个“首选”。

答案 2 :(得分:0)

既然你有兴趣找到“最受欢迎的人”,这是否意味着你只对“前几名”感兴趣,例如前5名,前10名等等?如果是这样,一种可能的方法是重新排序事物,以便你按照类似的方式进行迭代,计算N,与之相关的朋友数量,然后只对它进行进一步处理,如果它进入正在运行的'顶部X'列表。棘手的部分是使用这样的循环结构有效地计算N(天真的实现会循环遍历每个朋友。对于每个朋友,对于每个喜欢......哎呀......)但是好处是如果N足够小,你可以放弃所有与内存相关的数据都不会对内存进行任何进一步的处理。也就是说,如果你有一个“前十名单”,并且你已经在该列表中添加了10个喜欢,并且当前喜欢的N小于“前10个列表”中的最小N,那么你知道这就像是不相关的。基本上,您进行交易时会进行一些冗余循环,以换取大幅减少的内存占用。这些循环也可以合理地并行化,所以可能额外的循环也不是那么糟糕。很难说如果没有尝试它对你的特定用例更有效,但如果“十大”风格的输出符合你的要求,可能值得在这个方向探索。