PageRank算法

总算有一个周末下午时间,决定亲手把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次后的结果对比,完全吻合。

PageRank算法_第1张图片

     

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

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

 

你可能感兴趣的:(数据结构,c,算法,存储,Graph,语言)