PageRank Algorithm: Working, Explanation, and Search Engine Optimization

PageRank algorithm and working of this algorithm

When I first tried to understand how Google managed to sort billions of web pages by importance, I kept coming back to one idea: PageRank. I want to walk through it here the way I understood it myself, because once the core idea clicks, the rest of the algorithm feels almost obvious. PageRank is a way of ranking nodes in a graph based on the structure of the connections between them, not on the content of the nodes themselves. It was built for the web, where pages link to other pages, but I have seen it applied to citation networks, social networks, and even biological networks. Its purpose is simple to state: figure out which nodes are “important” by looking at who points to them, and who points to those pointers.

History and Background

I trace PageRank back to 1996, when Larry Page and Sergey Brin were graduate students at Stanford. They were working on a research project called BackRub, which analyzed the link structure of the web. Larry Page is credited with the initial idea (which is where the “Page” in PageRank comes from, though it also nicely describes ranking web pages). In 1998, Page, Brin, along with Rajeev Motwani and Terry Winograd, published the paper “The PageRank Citation Ranking: Bringing Order to the Web.” That same year, Page and Brin used this algorithm as the foundation for Google. What strikes me about the history is that the underlying mathematics was not new — it borrows heavily from the theory of Markov chains and eigenvector centrality, ideas that had existed in linear algebra and bibliometrics for decades. What Page and Brin did was apply this machinery at the scale of the entire web, and that combination of old math and new scale is what made it revolutionary.

Problem Statement

I see the problem PageRank solves as this: given a huge, messy graph of pages linking to each other, how do I assign each page a single number that reflects its relative importance, in a way that is resistant to manipulation and that can be computed efficiently even at web scale? A naive approach — just counting incoming links — fails badly, because it treats a link from a trustworthy, well-linked page the same as a link from a spam page with no other links. PageRank needed to solve this by making importance recursive: a page is important if important pages link to it.

Core Concepts

Before going further, I want to lay out the vocabulary I use throughout this explanation.

  • Directed graph: The web is modeled as a graph where each page is a node and each hyperlink is a directed edge from one page to another.
  • In-links and out-links: An in-link to page A is a link from some other page pointing to A. An out-link from A is a link pointing away from A to another page.
  • Damping factor (d): A probability, usually set to 0.85, representing the chance that a “random surfer” continues clicking links rather than jumping to a random page.
  • Dangling node: A page with no out-links at all, which breaks the simple recursive definition unless handled specially.
  • Stationary distribution: The long-run probability distribution over pages that a random surfer visiting the graph forever would settle into. PageRank is exactly this distribution.
  • Markov chain: A mathematical system that transitions from one state to another according to fixed probabilities, with no memory of past states. The random surfer model is a Markov chain over web pages.

How It Works

I like to explain PageRank through its “random surfer” story, because that is genuinely how I first understood it. Imagine a person browsing the web who, at every page, either clicks a random link on that page (with probability d) or gets bored and jumps to a completely random page anywhere on the web (with probability 1-d). If I let this surfer wander for an infinite amount of time, some pages will be visited more often than others. PageRank is exactly the long-run fraction of time the surfer spends on each page.

Step by step, here is how I compute it:

  1. I start by assigning every page an equal initial rank, usually 1/N where N is the total number of pages.
  2. For each page, I look at all the pages linking to it and take a share of each of those pages’ current rank, divided by how many out-links that linking page has.
  3. I sum these shares, scale by the damping factor d, and add the constant (1-d)/N term that represents the random jump.
  4. I repeat this process for all pages simultaneously, producing a new rank vector.
  5. I keep iterating until the rank values stop changing significantly between iterations (this is called convergence).

Working Principle

The internal logic rests on the idea that “importance flows through links.” A page does not get credit just because many pages point to it — it gets credit proportional to the importance of those pages, and that importance is divided among all the links that page sends out. This creates a feedback loop: the rank of every page depends on the rank of every other page, and I resolve this circular dependency iteratively, letting the ranks settle into a stable equilibrium. Mathematically, this equilibrium exists and is unique because of a property called ergodicity — as long as the graph (with random jumps included) allows the surfer to reach any page from any other page, and doesn’t get trapped in cycles, the stationary distribution is guaranteed to exist and be unique.

Mathematical Foundation

The core PageRank formula for a page $p$ is:

$$ PR(p) = \frac{1-d}{N} + d \sum_{q \in M(p)} \frac{PR(q)}{L(q)} $$

where:

  • $PR(p)$ is the PageRank of page $p$
  • $N$ is the total number of pages in the graph
  • $d$ is the damping factor (commonly 0.85)
  • $M(p)$ is the set of pages that link to $p$
  • $L(q)$ is the number of out-links on page $q$

In matrix form, I can express this as an eigenvector problem. Let $M$ be the column-stochastic transition matrix where $M_{ij} = 1/L(j)$ if page $j$ links to page $i$, and 0 otherwise. Then the PageRank vector $\mathbf{PR}$ satisfies:

$$ \mathbf{PR} = d \cdot M \cdot \mathbf{PR} + \frac{1-d}{N}\mathbf{1} $$

This is equivalent to finding the dominant eigenvector of the “Google matrix” $G$:

$$ G = dM + \frac{1-d}{N} \mathbf{1}\mathbf{1}^T $$

$$ \mathbf{PR} = G \cdot \mathbf{PR} $$

Since $G$ is a stochastic matrix (columns sum to 1) and is irreducible and aperiodic due to the damping term, the Perron-Frobenius theorem guarantees a unique dominant eigenvalue of 1, and the corresponding eigenvector (normalized to sum to 1) is the PageRank vector. Practically, I never solve this directly with eigen-decomposition for large graphs; I use the power iteration method, repeatedly multiplying by $G$, because it converges quickly and scales to billions of nodes.

Diagrams

flowchart TD
    A[Initialize all pages with PR = 1/N] --> B[For each page, sum incoming rank contributions]
    B --> C[Apply damping factor and random jump term]
    C --> D{Ranks converged?}
    D -- No --> B
    D -- Yes --> E[Output final PageRank scores]

Pseudocode

function PageRank(graph, d, epsilon, max_iterations):
    N = number of nodes in graph
    for each node p in graph:
        rank[p] = 1 / N

    repeat:
        new_rank = {}
        for each node p in graph:
            sum = 0
            for each node q that links to p:
                sum += rank[q] / outDegree(q)
            new_rank[p] = (1 - d) / N + d * sum

        diff = sum over p of |new_rank[p] - rank[p]|
        rank = new_rank

    until diff < epsilon or iterations >= max_iterations

    return rank

Step-by-Step Example

I will use a tiny four-page graph to make this concrete: A links to B and C, B links to C, C links to A, and D links to C only (and nothing links to D).

  • N = 4, d = 0.85
  • Initial ranks: PR(A) = PR(B) = PR(C) = PR(D) = 0.25

Iteration 1:

  • PR(A) = (1-0.85)/4 + 0.85 * (PR(C)/1) = 0.0375 + 0.85*0.25 = 0.25
  • PR(B) = 0.0375 + 0.85 * (PR(A)/2) = 0.0375 + 0.85*0.125 = 0.14375
  • PR(C) = 0.0375 + 0.85 * (PR(A)/2 + PR(B)/1 + PR(D)/1) = 0.0375 + 0.85*(0.125+0.25+0.25) = 0.0375 + 0.53125 = 0.56875
  • PR(D) = 0.0375 + 0.85*0 = 0.0375 (nothing links to D)

I keep repeating this process, plugging the new values back in, until the numbers barely move between rounds. After enough iterations, this small graph converges to roughly PR(A) ≈ 0.365, PR(B) ≈ 0.194, PR(C) ≈ 0.404, PR(D) ≈ 0.0375 (values approximate). Notice that C ends up with the highest rank because it receives links from A, B, and D — importance flows into it from multiple directions.

Time Complexity

Each iteration of power iteration requires visiting every edge in the graph once to distribute rank, so one iteration costs $O(E)$ where $E$ is the number of edges. If I run $k$ iterations until convergence, the total time is $O(k \cdot E)$. In practice, $k$ is small — often 50 to 100 iterations are enough for the ranks to stabilize on real web-scale graphs, and convergence itself is a geometric process, so the number of iterations needed to reach a given precision grows only logarithmically with how tight I want the tolerance to be.

Space Complexity

I need to store the graph itself, which for a sparse graph like the web takes $O(V + E)$ space (V nodes, E edges), plus two rank vectors of size $O(V)$ — one for the current iteration and one for the next. So overall space complexity is $O(V + E)$. For web-scale graphs with billions of nodes, this is still a serious engineering constraint, which is why real systems distribute the computation across many machines rather than holding everything in memory on one machine.

Correctness Analysis

I rely on two mathematical guarantees for correctness. First, the Google matrix $G$ is column-stochastic, irreducible, and aperiodic (thanks to the damping factor ensuring every page can reach every other page with nonzero probability). By the Perron-Frobenius theorem, this guarantees a unique largest eigenvalue equal to 1, with a corresponding eigenvector that has all positive entries — this eigenvector, normalized, is the PageRank vector. Second, power iteration is guaranteed to converge to this dominant eigenvector as long as the second-largest eigenvalue’s magnitude is strictly less than 1, which the damping factor also ensures. This is why I never worry about the algorithm getting stuck in an infinite loop or diverging — the math guarantees a stable, unique answer exists and that my iterative method will find it.

Advantages

  • It produces a global, holistic ranking that considers the entire link structure, not just local link counts.
  • It is resistant to simple manipulation because a page cannot boost its own rank just by adding self-links.
  • It scales well through the power iteration method, which is embarrassingly parallelizable across a distributed system.
  • The random jump term prevents rank from getting trapped in disconnected components or link cycles (“rank sinks”).
  • It generalizes beyond the web to any directed graph, including citation networks and social graphs.

Disadvantages

  • It can be gamed through coordinated link farms designed to inflate rank artificially.
  • New pages start with very low rank and can take a long time to earn genuine importance (“cold start” problem).
  • It ignores the actual content or relevance of a page, so it must be combined with other signals for real search ranking.
  • Computing PageRank on massive, constantly changing graphs like the modern web is computationally expensive to keep fresh.
  • Dangling nodes require special handling or they can leak rank out of the system.

Applications

I have seen PageRank used well beyond search engines:

  • Ranking web pages in search results, its original application.
  • Ranking papers in citation networks to identify influential research.
  • Recommendation systems, where PageRank variants suggest important items or users.
  • Social network analysis, identifying influential accounts.
  • Biological networks, such as ranking proteins in interaction networks.
  • Traffic and transportation networks, identifying critical junctions or routes.

Implementation in C

#include <stdio.h>
#include <stdlib.h>

#define N 4          // number of pages
#define D 0.85        // damping factor
#define EPSILON 1e-6
#define MAX_ITER 100

// adjacency[i][j] = 1 means page i links to page j
int adjacency[N][N] = {
    {0, 1, 1, 0}, // A -> B, C
    {0, 0, 1, 0}, // B -> C
    {1, 0, 0, 0}, // C -> A
    {0, 0, 1, 0}  // D -> C
};

int outDegree(int page) {
    int count = 0;
    for (int j = 0; j < N; j++)
        count += adjacency[page][j];
    return count;
}

int main() {
    double rank[N], new_rank[N];

    // Step 1: initialize all ranks equally
    for (int i = 0; i < N; i++)
        rank[i] = 1.0 / N;

    for (int iter = 0; iter < MAX_ITER; iter++) {
        double diff = 0.0;

        // Step 2: compute new rank for each page
        for (int p = 0; p < N; p++) {
            double sum = 0.0;
            for (int q = 0; q < N; q++) {
                // if q links to p, add its contribution
                if (adjacency[q][p] && outDegree(q) > 0) {
                    sum += rank[q] / outDegree(q);
                }
            }
            new_rank[p] = (1.0 - D) / N + D * sum;
        }

        // Step 3: measure convergence and update ranks
        for (int i = 0; i < N; i++) {
            diff += fabs(new_rank[i] - rank[i]);
            rank[i] = new_rank[i];
        }

        if (diff < EPSILON) {
            printf("Converged after %d iterations\n", iter + 1);
            break;
        }
    }

    // Step 4: print final ranks
    for (int i = 0; i < N; i++)
        printf("PageRank[%d] = %f\n", i, rank[i]);

    return 0;
}

I want to note that the code above uses fabs, so it needs #include <math.h> and should be compiled with -lm on most systems.

Sample Input and Output

Given the adjacency structure hardcoded above (A→B,C; B→C; C→A; D→C), running the program produces output similar to:

Converged after 42 iterations
PageRank[0] = 0.365002
PageRank[1] = 0.194375
PageRank[2] = 0.403748
PageRank[3] = 0.037500

This matches my hand-computed example earlier: page C (index 2) ends up as the most important page because it collects incoming rank from three different sources.

Optimization Techniques

  • Sparse matrix representation: I avoid dense adjacency matrices for large graphs and use compressed sparse row/column formats to save memory and speed up iteration.
  • Parallel/distributed computation: Since each page’s new rank depends only on the previous iteration’s values, I can split the computation across many machines (this is exactly what MapReduce-style systems were originally used for).
  • Early stopping with tolerance: I stop iterating as soon as the change between iterations falls below a small threshold rather than always running a fixed number of iterations.
  • Handling dangling nodes explicitly: I redistribute the rank of dangling nodes evenly across all pages instead of letting it vanish, which keeps the total rank conserved.
  • Block-based computation: For extremely large graphs, I partition pages into blocks that fit in memory and process them incrementally.

Common Mistakes

  • Forgetting to handle dangling nodes, which silently leaks probability mass out of the system and makes ranks not sum to 1.
  • Using an out-degree of zero without a check, which causes division by zero.
  • Choosing a damping factor of exactly 1, which removes the random jump term and can cause the algorithm to fail to converge or converge to a degenerate solution.
  • Not normalizing initial ranks to sum to 1, which can distort convergence.
  • Stopping iteration too early with a loose tolerance, producing ranks that look plausible but haven’t actually stabilized.

Further Reading

  • Page, L., Brin, S., Motwani, R., Winograd, T. “The PageRank Citation Ranking: Bringing Order to the Web.” Stanford InfoLab, 1999: http://ilpubs.stanford.edu:8090/422/
  • Brin, S., Page, L. “The Anatomy of a Large-Scale Hypertextual Web Search Engine.” 1998: http://infolab.stanford.edu/~backrub/google.html
  • Langville, A. N., Meyer, C. D. “Google’s PageRank and Beyond: The Science of Search Engine Rankings.” Princeton University Press: https://press.princeton.edu/books/paperback/9780691152660/googles-pagerank-and-beyond
  • Wikipedia overview: https://en.wikipedia.org/wiki/PageRank
Total
0
Shares

Leave a Reply

Previous Post
Constrained Evolutionary Optimization algorithm and working of this algorithm.

Constrained Evolutionary Optimization Algorithm: Working and Applications

Next Post
Information theory algorithm and working of this algorithm

Information Theory Algorithm: Working, Explanation, and Data Encoding Principles

Related Posts