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;//這裏返回的就是推薦關注的用戶標識啦
    }

上述純屬自己瞎想了寫的。。代碼很醜陋,但是最終還是能實現,哈哈。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章