PageRank算法

来源:互联网 发布:php 通过接口查询数据 编辑:程序博客网 时间:2024/05/02 02:56

总算有一个周末下午时间,决定亲手把pagerank算法实现一下。 之前只是看过思路,并一直使用同事的实现版本。

 

关于PageRank的介绍,请看

http://zh.wikipedia.org/wiki/PageRank
http://baike.baidu.com/view/1518.htm

 

不多废话了,直接进入正题,C++实现。

公式采用:

PR(A) = (1-d) +d(PR(t1)/C(t1) + ... + PR(tn)/C(tn))

样例,采用 http://zh.wikipedia.org/wiki/PageRank 中介绍的 A, B, C, D 四个站点,另外图采用邻接表存储方式(不是邻接矩阵,可根据习惯调整)

详情请看:http://www.webworkshop.net/pagerank.html

代码实现:C++语言: 贴彩色代码可用:http://fayaa.com/code/new/

为了方便构建图,使用了STL的数据结构,希望不会造成阅读障碍。

PageRank.h:

C++语言: 高亮代码由发芽网提供
#include <vector>
#include <set>
#include <string>
#include <iostream>

using namespace std;

// use graph store webpage, weight representlink times
class Node 
{
public:
    explicit Node(string name, double pr = 1):name_(name), page_rank_(pr){}

    ~Node()
    {
        linkin_nodes_.clear();
    }
    void InsertLinkdInNode(Node* node) 
    {
        //如果没有链接
        if (linkin_nodes_.find(node) == linkin_nodes_.end()) 
        {
            linkin_nodes_.insert(node);
        }
        node->InsertLinkOutNode(this);
    }

    void InsertLinkOutNode(Node* node) 
    {
        //如果没有链接
        if (linkout_nodes_.find(node) == linkout_nodes_.end()) 
        {
            linkout_nodes_.insert(node);
        }
    }

    double GetPageRank()
    {
        return page_rank_;
    }

    void SetPageRank(double pr)
    {
        page_rank_ = pr;
    }

    double CalcRank()
    {
        double pr = 0;
        set<Node*>::const_iterator citr = linkin_nodes_.begin();
        for (; citr != linkin_nodes_.end(); ++citr)
        {
            Node * node = *citr;
            pr += node->GetPageRank()/node->GetOutBoundNum();
        }
        return pr;
    }

    size_t GetOutBoundNum() 
    {
        return linkout_nodes_.size();
    }

    size_t GetInBoundNum() 
    {
        return linkin_nodes_.size();
    }
    
    void PrintNode()
    {
        cout << "Node:" << name_ << " 's pagerank is: " << page_rank_ << endl; 
    }
private:
    string name_;
    set<Node*> linkin_nodes_;
    set<Node*> linkout_nodes_;
    double page_rank_;
};

class PageRank
{
public:
    PageRank(double q=0.85);
    ~PageRank(void);
    void Calc(vector<Node*> & nodes, int n);
    double Calc(Node* node);
    void PrintPageRank(vector<Node*> & nodes);
private:
    double q_; //阻尼系数
};

 

PageRank.cpp

C++语言: 高亮代码由发芽网提供
#include "PageRank.h"
#include <iostream>

PageRank::PageRank(double q) : q_(q)
{
    // q_ must < 1
}


PageRank::~PageRank(void)
{
}

// 迭代计算n次
void PageRank::Calc(vector<Node*> & nodes, int n)
{
    for (int i=0; i<n; ++i) 
    {
        vector<Node*>::const_iterator citr = nodes.begin();
        for (; citr!=nodes.end(); ++citr) 
        {
            Node * node = *citr;
            Calc(node);
        }
    }
}

void PageRank::PrintPageRank(vector<Node*> & nodes)
{
    double total_pr = 0;
    vector<Node*>::const_iterator citr = nodes.begin();
    for (; citr!=nodes.end(); ++citr) 
    {    
        Node * node = *citr;
        node->PrintNode();
        total_pr += node->GetPageRank();
    }
    cout << "Total PR:" << total_pr << endl;
}

double PageRank::Calc(Node * node)
{
    double pr = node->CalcRank();
    if (pr < 0.00000000000000000000001 && pr > -0.00000000000000000000001//pr == 0
    {
        pr = 1-q_;
    }
    else 
    {
        pr = pr * q_ + 1-q_;
    }
    node->SetPageRank(pr);
    return pr;
}

main.cpp

C++语言: 高亮代码由发芽网提供
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include "PageRank.h"

using namespace std;

void InitGraph(vector<Node*> & nodes) 
{// 邻接表存储方式
    // example 1

    Node * a = new Node("A");
    Node * b = new Node("B");
    Node * c = new Node("C");
    Node * d = new Node("D");
    nodes.push_back(a);
    nodes.push_back(b);
    nodes.push_back(c);
    nodes.push_back(d);
    // link in node
    // a <- b, c, d

    a->InsertLinkdInNode(b);
    a->InsertLinkdInNode(c);
    a->InsertLinkdInNode(d);
    // b <- d
    b->InsertLinkdInNode(d);
    // c <- b, d
    c->InsertLinkdInNode(b);
    c->InsertLinkdInNode(d);
}

void TestPageRank()
{
    // build graph
    vector<Node*> nodes;
    InitGraph(nodes);
    PageRank pr;
    // 迭代计算5次 pagerank
    pr.Calc(nodes, 40);
    pr.PrintPageRank(nodes);
}

int main(int argc, const char ** argv)
{
    TestPageRank();
    return 0;
}

 

运行结果验证: http://www.webworkshop.net/pagerank_calculator.php?lnks=9,11,17,25,26,27&ilnks=&iblprs=&pgnms=&pgs=4&initpr=1&its=40&type=simple

截图:下面两个结果为初始pr值1,迭代计算40次后的结果对比,完全吻合。


     

这里只实现了simple mode,对于real mode等进一步探索,感兴趣的读者按实际需求进一步研究吧。

希望对于不熟练编程实现的人,能起到入门参考作用。