thinkphp利用并查集实现推荐关注

最近自己在写网站,用的thinkphp3.2,水了两年才开始接触除开课设和写题以外的东西。
网站里写了关注和粉丝之类的东西。然后想到微博有推荐关注这么一回事。虽然不知道微博是什么思路实现的,也不知道实现的原理。但想到平时写题遇到的分类的问题都是用并查集来解决的。

首先要实现粉丝关注的功能。下面是实现这个关系数据库里的表。

数据库表:

create table tp2_follow(
foid int not null auto_increment primary key,		//关注号,主码
followmyid int,		//如果有个关系是我关注你,那么followmyid就是我的用户标识
followyouid int,		//followyouid顾名思义就是关注对象的用户标识
followflag int default 0		//默认0,表示未关注,1表示关注,主要是为了取消关注后变更为0。
) default charset=utf8;

实现粉丝关注后,先想一想推荐关注的实现:
如果当前登录的用户是1,那么从数据库中查找与用户1相关的并且用户1未关注的人,这些人就是需要推荐给用户1关注的。
与用户1相关的并且用户1未关注的人,这么解释吧,现在有关系:1关注2,2关注3,2关注4,那么1、2、3、4就是一个集合,他们都互相是有关系的,是一个朋友圈。但是1没有关注3、4,于是将3、4推荐给1关注。
这种算谁和谁是一个集合的问题,就需要利用并查集了。并查集用c语言实现的话,主要是2个函数,一个find,一个mid,具体实现的思路这里就不多说了,贴一下c的代码:

find函数:

int find(int x){//查找祖先节点
	if(pre[x] != x)pre[x] = find(x);
	return pre[x];
}

mix函数:

void mix(int x, int y){//合并2个节点
	int fx = find(x), int fy = find(y);
	if(fx != fy) pre[fx] = fy;
}

那么thinkphp只需要仿照着c的思路写就ok了:

php的find函数:

    public function bcjfind(&$pre = array(), $x)
    {
        if($pre[$x] != $x)
        {
            $pre[$x] = $this->bcjfind($pre, $pre[$x]);
        }
        return $pre[$x];
    }

php的mix函数:

    public function bcjmix(&$pre = array(), $x, $y)
    {
        $fx = $this->bcjfind($pre, $x);
        $fy = $this->bcjfind($pre, $y);
        if($fx != $fy)
        {
            $pre[$fx] = $fy;
        }
    }

实现这个功能的函数:

    public function recommend()
    {
    	$id = $_SESSION["uid"];//登录这个用户的用户标识
        $allusernum = D("user")->queryfoundmaxid();//对数据库的操作,查找到用户标识中最大的标识,也就是有多少个用户
        for($row=1; $row<=$allusernum; $row++)//并查集的初始化,让所有节点的祖先等于他自己
        {
            $pre[$row] = $row;
        }
        $allfollowdata = D("user")->foundallfollowdata();//把所有关注关系成立的数据查出来,也就是followflag为1的关系数据
        for($row=0; $row<count($allfollowdata); $row++)
        {
            $this->bcjmix($pre, $allfollowdata[$row]["followmyid"], $allfollowdata[$row]["followyouid"]);//用并查集把相关的人合为一个集合
        }
        $i = 0;
        $tmp = $this->bcjfind($pre, $id);//查找登录用户标识的祖先
        for($row=1; $row<=$allusernum; $row++)//从小到大把所有用户标识遍历一遍,只要是和登录者用户标识祖先相同的就给存下来
        {
            if($row != $_SESSION["uid"] && $pre[$row] == $tmp && D("user")->checkmenotfollowyou($_SESSION["uid"], $row))
            {
                $data[$i++]["id"] = $row;
            }
        }
        $go = array();
        for($row=0; $row < 3; $row++)//这个循环其实可以不用要,我主要是为了每次随机推荐三个人,控制推荐人数的。
        {
            if($row < count($data))
            {
                $flag = 1;
                while($flag)
                {
                    $tt = $data[rand()%count($data)]["id"];
                    $flag = 0;
                    for($r = 0; $r < $row; $r++)
                    {
                        if($go[$r]["id"] == $tt)
                        {
                            $flag = 1;
                        }
                    }
                    $go[$row]["id"] = $tt;
                }
            }
        }
        return $go;//这里返回的就是推荐关注的用户标识啦
    }

上述纯属自己瞎想了写的。。代码很丑陋,但是最终还是能实现,哈哈。

猜你喜欢

转载自blog.csdn.net/xiaotudeluobo/article/details/84202763