程序员面试金典: 9.10 扩展性与存储限制 10.2寻找社交网站中的朋友路径

#include <iostream>
#include <stdio.h>
#include <map>
#include <vector>

using namespace std;
/*
问题:你会如何设计诸如Facebook或Linkedln的超大型社交网站?请设计一种算法,展示两个人之间的"连接关系"或"社交路径"
     (比如:,我->鲍勃->苏珊->杰森->你)
分析:实际是一种搜索。最简单的办法就是暴力破解。遍历我的每一个朋友,然后对于我的每一个朋友继续遍历。
      这样的话,时间复杂度为O(2^n),必须要剪枝,关键是如何剪枝呢?
	  深度优先搜索或广度优先搜索。 广度优先搜索用于计算最优问题,深度优先搜索用于计算是否有解问题。
	  如果考虑每个人的朋友较少,即总人数较少的情况下,是可以用广度优先搜索实现。
书上解法:
          步骤1:如何在大数据的情况下,找到自己的朋友。
         人数非常多的时候,每个人的信息一般按照人的id分配在不同的机器上,比如按某种哈希散列后,存储在不同地方。
		 最关键就是<人的id,机器id>,<机器id,人的id>,根据人的id想要获取人的信息,需要做以下处理:
		 根据人的id找到机器id,根据机器id找到机器,获取机器上保存的<人的id,人>映射,获取人的信息。
		 这是服务器类。
		 步骤2:采用广度优先搜索,不用深度优先搜索的原因是两个人可能直接是朋友,如果深度优先搜索,可能搜索几百万结点
		         后发现不是,再继续搜,效果太差了

关键:
1 
步骤1:如何在大数据的情况下,找到自己的朋友。
人数非常多的时候,每个人的信息一般按照人的id分配在不同的机器上,比如按某种哈希散列后,存储在不同地方。
最关键就是<人的id,机器id>,<机器id,人的id>,根据人的id想要获取人的信息,需要做以下处理:
根据人的id找到机器id,根据机器id找到机器,获取机器上保存的<人的id,人>映射,获取人的信息。
这是服务器类。
步骤2:采用广度优先搜索,不用深度优先搜索的原因是两个人可能直接是朋友,如果深度优先搜索,可能搜索几百万结点
		后发现不是,再继续搜,效果太差了
2 
人类: 每个人包含自己的id,以及朋友id列表,而不是朋友列表,因为存储朋友列表会浪费空间
机器类:存储了<人的id,人>的映射,包含自身机器id
服务类:服务器类,存储<人的id,机器id>,<机器id,人的id>的映射
       服务类提供的最主要功能是根据用户id获取用户信息

3 扩展问题:
1)划分用户和机器,尽量按国家,城市,进行划分,减少跳转
2)找到同一机器上的多个朋友后,再跳转
3)广度优先搜索标记访问结点不要直接编辑数据,可以用散列表<id,该id是否访问过>
4)优先选择自己朋友中拥有朋友个数较多的人作为起点遍历
5)搜索到何时放弃,即存在剪枝,比如最多深度为100时就不再搜索
*/

//人,每个人包含自己的id,以及朋友id列表,而不是朋友列表,因为存储朋友列表会浪费空间
class Person
{
public:
	Person(int id):_id(id){}
	void addFriend(int id)
	{
		friends.push_back(id);
	}
	int _id;
	vector<int> friends;
};

//机器,存储了<人的id,人>的映射,包含自身机器id
class Machine
{
public:
	Machine():_isNull(false){}
	//可以根据人的id获取人
	Person getPerson(int personId)
	{
		map<int , Person>::iterator it = personIdToPerson.find(personId);
		if(it != personIdToPerson.end())
		{
			return it->second;
		}
		else
		{
			return NULL;
		}
	}
private:
	map<int , Person> personIdToPerson;
	//机器包含机器id
	int _machineId;
public:
	bool _isNull;
};

//服务器类,存储<人的id,机器id>,<机器id,人的id>的映射
class Server
{
public:
	Server(){}
	void init(){}
	int getMachineId(int personId)
	{
		map<int , int>::iterator it = personIdToMachineId.find(personId);
		if(it != personIdToMachineId.end())
		{
			return it->second;
		}
		else
		{
			return -1;
		}
	}

	Machine getMachine(int machineId)
	{
		map<int, Machine>::iterator it = machineIdToMachine.find(machineId);
		if(it != machineIdToMachine.end() )
		{
			return it->second;
		}
		else
		{
			Machine machine;
			machine._isNull = true;
			return machine;
		}
	}

	//服务类提供的最主要功能是根据用户id获取用户信息
	Person getPersonByPersonId(int personId)
	{
		int machineId = getMachineId(personId);
		if(-1 == machineId)
		{
			return NULL;
		}
		Machine machine = getMachine(machineId);
		Person person = machine.getPerson(personId);
		return person;
	}
private:
	map<int , int> personIdToMachineId;
	map<int, Machine> machineIdToMachine;
};

int main(int argc , char* argv[])
{
	getchar();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值