PAT (Advanced Level) Practice 1129 Recommendation System set应用及运算符重载

一、概述

设计一个简单的推荐算法。根据点击次数给出推荐。

观察问题可以得到直观的解决方案:记录商品编号,对应的点击次数累加,输出点击次数最高的前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);
			}
		}
	 } 
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值