从容器中获取前5个算法?

时间:2011-08-16 07:20:41

标签: c++ algorithm sorting

我有一个类(对象),User。该用户有2个私有属性,“名称”和“受欢迎程度”。我将对象存储到向量(容器)中。

从容器中,我需要找到前5位最受欢迎的用户,我该怎么做? (我有一个丑陋的代码,我会在这里发布,如果你有更好的方法,请告诉我。如果你认为矢量不是一个好的选择,请随意使用其他容器,但请仅使用:map或multimap,列表,向量或数组,因为我只知道如何使用它们。)我目前的代码是:

int top5 = 0, top4 = 0, top3 = 0, top2 = 0, top1 = 0;
vector<User>::iterator it;

for (it = user.begin(); it != user.end(); ++it) 
{
    if( it->getPopularity() > top5){
        if(it->getPopularity() > top4){
            if(it->getPopularity() > top3){
                if(it->getPopularity() > top2){
                    if(it->getPopularity() > top1){
                        top1 = it->getPopularity();
                        continue;
                    } else {
                        top2 = it->getPopularity();
                        continue;
                    }
                } else {
                    top3 = it->getPopularity();
                    continue;
                }
            }
        } else {
            top4 = it->getPopularity();
            continue;
        }
    } else {
        top5 = it->getPopularity();
        continue;
    }
}

我知道代码很难看并且可能容易出错,因此如果您有更好的代码,请与我们分享(我们== cpp newbie)。感谢

8 个答案:

答案 0 :(得分:9)

您可以使用std::partial_sort算法对矢量进行排序,以便对前五个元素进行排序,其余元素保持未排序。这样的事情(未经测试的代码):

bool compareByPopularity( User a, User b ) {
    return a.GetPopularity() > b.GetPopularity();
}

vector<Users> getMostPopularUsers( const vector<User> &users, int num ) {
    if ( users.size() <= num ) {
        sort( users.begin(), users.end(), compareByPopularity );
    } else {
        partial_sort( users.begin(), users.begin() + num, users.end(), 
                      compareByPopularity );
    }
    return vector<Users>( users.begin(), users.begin() + num );
}

答案 1 :(得分:2)

为什么不根据受欢迎程度对矢量进行排序(std::sort或您自己的快速排序实施)并获取前5个值?

示例:

bool UserCompare(User a, User b) { return a.getPopularity() > b.getPopularity(); }
...
std::sort(user.begin(), user.end(), UserCompare);
// Print first 5 users

答案 2 :(得分:2)

首先,缓存it->getPopularity(),这样您就不必再重复它了。

其次(这更为重要):您的算法存在缺陷。当您找到新的top1时,您需要在保存新的top1之前将旧top1向下推到#2插槽,但在此之前您必须推送旧top2 {1}}到#3插槽等等。这只适用于新的top1。对于新的top2,新的top3等,您将不得不做类似的事情。您可以粘贴的唯一一个而不用担心将事情推到列表中的是您获得新的{{ {1}}。正确的算法很毛茸茸。也就是说,当top5是一个数组而不是一堆单独的值时,正确的算法更容易实现。

第三(这比第二点更重要):你不应该关心性能,至少不是最初的。这样做的简单方法是对整个列表进行排序,然后从顶部排出前五个。如果这个次优但简单的算法不会影响您的表现,那就完成了。不要使用丑陋但快速的第一个N算法,除非性能要求你将简单的解决方案抛到窗外。

最后(这是最重要的一点):当列表中的元素数远多于5时,快速的第一个N算法才会很快。默认的排序算法非常快。在下推第一个N算法变得有利之前,必须浪费大量时间对几十个/几百个你不关心的项目进行排序。换句话说,该下推插入排序算法很可能是过早不优化的情况。

答案 3 :(得分:2)

如果您只想要前5个热门用途,请使用std :: partial_sort()。

    class User
    {
    private:
        string name_m;
        int popularity_m;
    public:
        User(const string& name, int popularity) : name_m(name), popularity_m(popularity) { }
        friend ostream& operator<<(ostream& os, const User& user)
        {
            return os << "name:" << user.name_m << "|popularity:" << user.popularity_m << "\n";
            return os;
        }

        int Popularity() const 
        {
            return popularity_m;
        }

    };

    bool Compare(const User& lhs, const User& rhs)
    {
        return lhs.Popularity() > rhs.Popularity();
    }

    int main()
    {
        // c++0x. ignore if you don't want it.
        auto compare = [](const User& lhs, const User& rhs) -> bool 
                  { return lhs.Popularity() > rhs.Popularity(); };

        partial_sort(users.begin(), users.begin() + 5, users.end(), Compare);

        copy(users.begin(), users.begin() + 5, ostream_iterator<User>(std::cout, "\n"));
    }

答案 4 :(得分:0)

对象进行排序,如果允许,可以使用库,然后只需选择前5个元素。如果你的容器太大,你可能会使用std :: list来完成这项工作。

编辑:@itsik你把我打到了秒:)

答案 5 :(得分:0)

执行此伪代码。

Declare top5 as an array of int[5] // or use a min-heap
Initialize top5 as 5 -INF

For each element A
   if A < top5[4]                  // or A < root-of-top5
      Remove top5[4] from top5     // or pop min element from heap
      Insert A to top              // or insert A to the heap

答案 6 :(得分:0)

好吧,我建议您通过使用数组或列表或向量来存储前五个来改进代码,就像这样

struct TopRecord
{
    int index;
    int pop;
} Top5[5];

for(int i = 0; i<5; i++)
{
    Top5[i].index = -1;
    // Set pop to a value low enough
    Top5[i].pop = -1;
}

for(int i = 0; i< users.size(); i++)
{
    int currentpop = i->getPopularity()
    int currentindex = i;
    int j = 0;
    int temp;

    while(j < 5 && Top5[j].pop < currentpop)
    {
        temp = Top5[j].pop;
        Top[j].pop = currentpop;
        currentpop = temp;

        temp = Top5[j].index;
        Top[j].index = currentindex;
        currentindex = temp;

        j++;
    }
}

答案 7 :(得分:0)

如果您的目标是性能,您也可以考虑使用随机选择,因为最初的随机选择对于有序统计而言足够好并且在线性时间内运行,您只需要运行5次。或者使用上面提供的partial_sort解决方案,无论哪种方式计数,都取决于您的目标。