一、概述
设计一个简单的推荐算法。根据点击次数给出推荐。
观察问题可以得到直观的解决方案:记录商品编号,对应的点击次数累加,输出点击次数最高的前K个。
可以使用数组存储,然后使用sort不断排序输出。也可以利用set实现。还有点麻烦。但是就当是练习set了吧。
二、分析
一件商品有两个属性:名称和点击次数。
set中要储存这两个。因此要使用结构体。但是正常来讲,set是有序的,那结构体怎么排序呢?这时就要我们告诉它排序的方法,也就是运算符重载。这有两种写法,为了和之前的sort-cmp联合记忆,我决定采用cmp结构体的形式。
运算符重载如下:
struct cmp
{
bool operator()(node a,node b)
{
if(a.num!=b.num)
return a.num>b.num;
else
return a.name<b.name;
}
};
//
//注意与sort的cmp对比
//
bool cmp(node a,node b)
{
if(a.num!=b.num)
return a.num>b.num;
else
return a.name<b.name;
}
可以看出,sort的cmp是一个函数,返回类型是bool;
set的cmp是一个结构体,结构体内部有一个函数,这个函数的返回值是bool,名称是operator,注意函数名称只能是这个。函数名称后要有一个空括号,然后才能接参数。因为我们实际上是重新定义了operator,所以名称不能错。里面和cmp就一样了。
这个cmp是放在set的第二个参数位置的。然后就可以开始输入了。这种类似结构体数组的输入已经有很多次了,无非是声明一个node,为其赋值,然后插入。关键就在于插入:
其实我觉得用set一点都没有方便的原因就在这里,set没法子搜索节点名称为x的节点,它要搜索就必须把节点的所有信息都给全,否则就搜不到。这样一来set的只保留一个相同元素的特点就没有用了——你输入三次5,节点的点击次数分别是1,2,3,它直接插入是插三个,而不是把名字为5的节点更新为1,2,3。由于这一点,我们要这样做才行:
开一个数组book,记录目前每件商品的点击次数。
每当输入一个新商品,声明一个节点把name和num分别赋值,book就是用于给num赋值的,然后精确查找,找到后erase,然后重新插入。没找到则返回set的end,那就直接插入,同时维护book数组。真麻烦,简直是脱裤子放屁。但是聊胜于无的一点是set是自动排序的,省的我们自己多次用sort了,也成吧。如下:
for(int i=0;i<N;i++)
{
if(i==0)
{
int m;
scanf("%d",&m);
book[m]++;
node newnode;
newnode.name=m;
newnode.num=1;
s.insert(newnode);
}
else
{
int m;
scanf("%d",&m);
printf("%d:",m);
int Ssize=s.size();
if(Ssize<=K)
{
set<node,cmp>::iterator it2;
for(it2=s.begin();it2!=s.end();it2++)
{
int name=(*it2).name;
printf(" %d",name);
}
printf("\n");
}
else
{
set<node,cmp>::iterator it2;
int j;
for(it2=s.begin(),j=0;j<K;it2++,j++)
{
int name=(*it2).name;
printf(" %d",name);
}
printf("\n");
}
set<node,cmp>::iterator it;
node newnode;
newnode.name=m;
newnode.num=book[m];
it=s.find(newnode);
if(it==s.end())
{
book[m]++;
newnode.num=book[m];
s.insert(newnode);
}
else
{
s.erase(it);
book[m]++;
newnode.num=book[m];
s.insert(newnode);
}
}
}
set的find()函数,参数类型和set一样,返回迭代器;
set的erase()函数,参数是迭代器,一般和find一起使用;
set的insert函数,这个就不说了。
注意一点是先输出再插入,否则会出错。
三、总结
就算是对set的一个整体练习吧,也学了下运算符重载,还是挺方便的。
PS:代码如下:
#include<stdio.h>
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;
struct node
{
int name;
int num=0;
};
struct cmp
{
bool operator()(node a,node b)
{
if(a.num!=b.num)
return a.num>b.num;
else
return a.name<b.name;
}
};
int book[50010]={0};
set<node,cmp> s;
int main()
{
int N,K;//N为总推荐数,K为推荐窗口
scanf("%d %d",&N,&K);
for(int i=0;i<N;i++)
{
if(i==0)
{
int m;
scanf("%d",&m);
book[m]++;
node newnode;
newnode.name=m;
newnode.num=1;
s.insert(newnode);
}
else
{
int m;
scanf("%d",&m);
printf("%d:",m);
int Ssize=s.size();
if(Ssize<=K)
{
set<node,cmp>::iterator it2;
for(it2=s.begin();it2!=s.end();it2++)
{
int name=(*it2).name;
printf(" %d",name);
}
printf("\n");
}
else
{
set<node,cmp>::iterator it2;
int j;
for(it2=s.begin(),j=0;j<K;it2++,j++)
{
int name=(*it2).name;
printf(" %d",name);
}
printf("\n");
}
set<node,cmp>::iterator it;
node newnode;
newnode.name=m;
newnode.num=book[m];
it=s.find(newnode);
if(it==s.end())
{
book[m]++;
newnode.num=book[m];
s.insert(newnode);
}
else
{
s.erase(it);
book[m]++;
newnode.num=book[m];
s.insert(newnode);
}
}
}
}