CEN207 Data Structures · Week 9

Week 9

Graph Algorithms

Order · Weights · Cycles · Backtracking

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Today's map

  • Order: topological sort (2 ways), cycle detection
  • Track groups: union-find
  • Cheapest connections: Kruskal, Prim (MST)
  • Cheapest paths: Dijkstra, Bellman-Ford, Floyd-Warshall
  • Reachability: strongly connected components, bipartite
  • Beyond paths: max flow, backtracking
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Before we start: what you know

  • Week 5: adjacency list, alphabetical neighbours
  • BFS: queue, fewest edges
  • DFS: recursion or explicit stack
  • Connected components: BFS/DFS from every unvisited vertex
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

The one new ingredient: weights

  • 6 of today's algorithms attach a number to every edge
  • A distance, a cost, a capacity
  • The question changes from "reachable?" to "cheapest?"
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

What this week reuses from Week 5

Week 5 tool Reused by
Adjacency list, alphabetical order Every algorithm this week
BFS queue Bipartite check, max-flow's augmenting path
DFS recursion Topo-sort, cycle detection, SCC, backtracking
Circle layout Every animation's graph drawing
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

1. Topological Sort

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

A question to start

Socks before shoes. Shirt before jacket.
No order between socks and shirt.

Is there always one order obeying every rule?

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

A short history

  • A. B. Kahn, 1962 — in-degree + queue
  • Build systems, package installers use this daily
  • The DFS-based alternative falls out of Tarjan's 1970s DFS framework
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Kahn's idea

  • A vertex with in-degree 0 has no unmet prerequisite
  • Place it now; this removes its outgoing edges
  • Every neighbour's in-degree drops by one
  • Newly-zero neighbours become eligible — enqueue them
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Kahn's code (C) — part 1/2

int topo_sort_kahn(Graph *g) {
    for (int i=0;i<g->vertex_count;i++) indeg[i]=0;
    for (int u=0;u<g->vertex_count;u++)
        for (AdjNode *n=g->adj[u]; n; n=n->next)
            indeg[n->to]++;
    front=rear=0; order_len=0;
    for (int v=0;v<g->vertex_count;v++)
        if (indeg[v]==0) enqueue(v);
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Kahn's code (C) — part 2/2

    while (front<rear) {
        int u=dequeue();
        order[order_len++]=u;
        for (AdjNode *n=g->adj[u]; n; n=n->next) {
            indeg[n->to]--;
            if (indeg[n->to]==0) enqueue(n->to);
        }
    }
    return order_len==g->vertex_count;
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Kahn's code (Java) — part 1/2

static boolean topoSortKahn(Graph g) {
    for (int i=0;i<g.vertexCount;i++) indeg[i]=0;
    for (int u=0;u<g.vertexCount;u++)
        for (AdjNode n=g.adj[u]; n!=null; n=n.next)
            indeg[n.to]++;
    front=rear=0; orderLen=0;
    for (int v=0;v<g.vertexCount;v++)
        if (indeg[v]==0) enqueue(v);
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Kahn's code (Java) — part 2/2

    while (front<rear) {
        int u=dequeue();
        order[orderLen]=u; orderLen++;
        for (AdjNode n=g.adj[u]; n!=null; n=n.next) {
            indeg[n.to]--;
            if (indeg[n.to]==0) enqueue(n.to);
        }
    }
    return orderLen==g.vertexCount;
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Kahn's algorithm

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Edge case: a cycle

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Real output: Kahn's algorithm

-- normal: 8 vertices, 10 edges, a valid DAG --
order: A B C D F E G H
all 8 vertices placed: a valid topological order

-- edge: 10 edges but a cycle exists, no full order --
order:
only 0 of 7 vertices placed -- a cycle exists
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

The DFS idea

  • Run recursive DFS (Week 5's DFS, one array added)
  • Record every vertex's finish time
  • Read finish times largest to smallest
  • A vertex finishes only after everything it points to
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

DFS topo-sort code (C) — dfs_visit

void dfs_visit(int u) {
    color_of[u]=1;
    for (AdjNode *n=cur_g->adj[u]; n; n=n->next) {
        if (color_of[n->to]==0) dfs_visit(n->to);
        else if (color_of[n->to]==1) has_cycle=1;
    }
    color_of[u]=2;
    finish[finish_len++]=u;
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

DFS topo-sort code (C) — the driver

void topo_sort_dfs(Graph *g) {
    cur_g=g;
    for (int i=0;i<g->vertex_count;i++) color_of[i]=0;
    finish_len=0; has_cycle=0;
    for (int v=0;v<g->vertex_count;v++)
        if (color_of[v]==0) dfs_visit(v);
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

DFS topo-sort code (Java) — dfsVisit

static void dfsVisit(int u) {
    colorOf[u]=1;
    for (AdjNode n=curG.adj[u]; n!=null; n=n.next) {
        if (colorOf[n.to]==0) dfsVisit(n.to);
        else if (colorOf[n.to]==1) hasCycle=true;
    }
    colorOf[u]=2;
    finish[finishLen]=u; finishLen++;
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

DFS topo-sort code (Java) — the driver

static void topoSortDfs(Graph g) {
    curG=g;
    for (int i=0;i<g.vertexCount;i++) colorOf[i]=0;
    finishLen=0; hasCycle=false;
    for (int v=0;v<g.vertexCount;v++)
        if (colorOf[v]==0) dfsVisit(v);
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

DFS topological sort

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Complexity & mistake

  • O(V + E) — both algorithms, one pass
  • Mistake: a topological order is not unique
  • Compare positions, never hard-code the exact sequence
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Mini question

Why does Kahn's algorithm use a queue, not just one recursive call?

(answer on the next slide)

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Answer

A DAG can have several independent sources at once.

The queue lets the algorithm interleave them in one pass, instead of finishing one branch before starting another.

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

2. Cycle Detection (Directed)

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

A question to start

Section 1's DFS detects that a cycle exists (a back edge).

Which vertices form it, in what order?

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

3-colour DFS with a path

  • White / gray (on the path) / black (finished)
  • Keep the current path in on_path[]
  • A back edge to a gray vertex: that vertex is an open ancestor
  • The path slice from there to here IS the cycle
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Cycle detection code (C) — part 1/2

int dfs_cycle(int u) {
    color_of[u]=1;
    on_path[path_top++]=u;
    for (AdjNode *n=cur_g->adj[u]; n; n=n->next) {
        if (color_of[n->to]==0) {
            if (dfs_cycle(n->to)) return 1;
        } else if (color_of[n->to]==1) {
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Cycle detection code (C) — part 2/2

            int i=path_top-1;
            while (on_path[i]!=n->to) i--;
            cycle_len=0;
            for (; i<path_top; i++)
                cycle[cycle_len++]=on_path[i];
            return 1;
        }
    }
    path_top--; color_of[u]=2;
    return 0;
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Cycle detection code (Java) — part 1/2

static boolean dfsCycle(int u) {
    colorOf[u]=1;
    onPath[pathTop]=u; pathTop++;
    for (AdjNode n=curG.adj[u]; n!=null; n=n.next) {
        if (colorOf[n.to]==0) {
            if (dfsCycle(n.to)) return true;
        } else if (colorOf[n.to]==1) {
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Cycle detection code (Java) — part 2/2

            int i=pathTop-1;
            while (onPath[i]!=n.to) i--;
            cycleLen=0;
            for (; i<pathTop; i++) {
                cycle[cycleLen]=onPath[i]; cycleLen++;
            }
            return true;
        }
    }
    pathTop--; colorOf[u]=2;
    return false;
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Cycle detection, directed graph

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Edge case: no cycle at all

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Real output: cycle detection

-- normal: 8 vertices, 10 edges, one cycle: C-D-F-C --
cycle found: D F C -> D

-- edge: 10 edges, entirely cycle-free (a DAG) --
no cycle found

-- edge: the smallest cycle, A-B-A (2 edges) --
cycle found: A B -> A
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Complexity & mistake

  • O(V + E) — one DFS, plus O(V) to extract a found cycle
  • Mistake: checking "not white" instead of "gray"
  • A black neighbour is finished and safe — not a cycle
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Mini question

Section 1's DFS topo-sort just sets has_cycle = 1. Why does THIS algorithm need the extra on_path[] stack at all?

(answer on the next slide)

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Answer

Knowing a cycle exists is not the same as knowing which vertices form it.

on_path[] keeps the current root-to-here chain available, so the moment a back edge is found, the cycle can be read straight off it.

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

3. Union-Find

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

A question to start

Kruskal's algorithm (coming up) must ask, over and over:

"Are these two vertices already connected by edges I picked?"

A fresh BFS every time would be correct — but slow.

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

A forest of parent pointers

  • find(v) walks parent pointers up to the root
  • Same root = same group
  • union(a, b) merges two groups: root points to root
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Two tricks

  • Union by rank: shorter tree hangs under the taller
  • Path compression: find re-points every visited node straight at the root
  • Together: O(α(n)) per operation — for all practical n, this is O(1)
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Union-find code (C) — find

int find(int v) {
    int root=v;
    while (parent_of[root]!=root) root=parent_of[root];
    while (parent_of[v]!=root) {
        int next=parent_of[v];
        parent_of[v]=root;
        v=next;
    }
    return root;
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Union-find code (C) — union_sets

void union_sets(int a, int b) {
    int ra=find(a), rb=find(b);
    if (ra==rb) return;
    if (rank_of[ra]<rank_of[rb]) parent_of[ra]=rb;
    else if (rank_of[ra]>rank_of[rb]) parent_of[rb]=ra;
    else { parent_of[rb]=ra; rank_of[ra]++; }
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Union-find code (Java) — find

static int find(int v) {
    int root=v;
    while (parentOf[root]!=root) root=parentOf[root];
    while (parentOf[v]!=root) {
        int next=parentOf[v];
        parentOf[v]=root;
        v=next;
    }
    return root;
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Union-find code (Java) — unionSets

static void unionSets(int a, int b) {
    int ra=find(a), rb=find(b);
    if (ra==rb) return;
    if (rankOf[ra]<rankOf[rb]) parentOf[ra]=rb;
    else if (rankOf[ra]>rankOf[rb]) parentOf[rb]=ra;
    else { parentOf[rb]=ra; rankOf[ra]++; }
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Real output: union-find

union(A, B): merged, new root = A
union(C, D): merged, new root = C
union(A, C): merged, new root = A
find(D) = A
union(B, H): already the same set (A)
final sets: A->A B->A C->A D->A E->A F->A G->A H->A
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Union-find: rank + path compression

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Complexity & mistake

  • ~O(1) amortised per operation, with both tricks
  • Mistake: union(a, b) comparing a, b directly
  • Must merge roots — find(a), find(b) — never raw arguments
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Mini question

Rank counts height, not the number of elements in a set. Why not just track set size instead?

(answer on the next slide)

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Answer

Size works too, and is a common alternative — "union by size" hangs the smaller set under the larger one.

Both give the same O(α(n)) guarantee; rank is the classical presentation because it directly bounds tree height, which is what find actually pays for.

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

4. Minimum Spanning Trees

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

A question to start

Connect n towns with power lines. Any pair could link directly, at a cost.

What is the cheapest set of lines that still connects everything?

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

A short history

  • Joseph Kruskal, 1956
  • Robert Prim, 1957 (rediscovering Jarník, 1930)
  • Same problem, two structurally different greedy solutions
  • Both provably safe: the cut property
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Kruskal's idea

  • Sort all edges by weight, once
  • Scan cheapest-first; add an edge unless it closes a cycle
  • Cycle check: union-find, near O(1)
  • Disconnected graph → a spanning forest
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Prim's idea

  • Grow one tree from a start vertex
  • Add the cheapest edge from inside to outside
  • key[v] = cheapest edge connecting v to the tree so far
  • Never reaches a different component: key stays "infinite"
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Kruskal's code (C) — part 1/2

int kruskal_mst(Edge *sorted, int edge_count,
                 Edge *mst_out, int *total_out) {
    for (int v=0;v<vertex_count;v++)
        { parent_of[v]=v; rank_of[v]=0; }
    qsort(sorted, edge_count, sizeof(Edge), cmp_weight);
    int mst_len=0, total=0;
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Kruskal's code (C) — part 2/2

    for (int i=0;i<edge_count;i++) {
        if (find(sorted[i].a)==find(sorted[i].b))
            continue;
        union_sets(sorted[i].a, sorted[i].b);
        mst_out[mst_len++]=sorted[i];
        total+=sorted[i].w;
    }
    *total_out=total;
    return mst_len;
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Kruskal's code (Java) — part 1/2

static int kruskalMst(Edge[] sorted,
                       Edge[] mstOut, int[] totalOut) {
    for (int v=0;v<vertexCount;v++)
        { parentOf[v]=v; rankOf[v]=0; }
    Arrays.sort(sorted, Comparator.comparingInt(
        (Edge e) -> e.w).thenComparingInt(e -> e.idx));
    int mstLen=0, total=0;
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Kruskal's code (Java) — part 2/2

    for (Edge e : sorted) {
        if (find(e.a)==find(e.b)) continue;
        unionSets(e.a, e.b);
        mstOut[mstLen]=e; mstLen++;
        total+=e.w;
    }
    totalOut[0]=total;
    return mstLen;
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Kruskal's MST

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Edge case: a spanning forest

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Real output: Kruskal's MST

-- normal: 7 vertices, 10 edges, one component --
MST edges: B-C:1 A-C:2 D-E:2 E-F:3 B-D:5 E-G:7
total weight = 20
components = 1

-- edge: 10 edges, 2 components -- a spanning FOREST --
MST edges: C-D:1 A-B:2 F-G:2 D-E:3 H-I:3 B-C:4 I-J:4 G-H:6
total weight = 25
components = 2 (a spanning forest)
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Prim's code (C) — part 1/2

int prim_mst(Graph *g, int start,
             Edge *mst_out, int *total_out) {
    for (int v=0;v<g->vertex_count;v++)
        { key_of[v]=INF; in_mst[v]=0; parent_of[v]=-1; }
    key_of[start]=0;
    int mst_len=0, total=0;
    for (int count=0;count<g->vertex_count;count++) {
        int u=min_key_vertex(g->vertex_count);
        if (u==-1 || key_of[u]==INF) break;
        in_mst[u]=1;
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Prim's code (C) — part 2/2

        if (parent_of[u]!=-1) {
            mst_out[mst_len].a=parent_of[u];
            mst_out[mst_len].b=u;
            mst_out[mst_len].w=key_of[u];
            mst_len++; total+=key_of[u];
        }
        for (AdjNode *n=g->adj[u]; n; n=n->next)
            if (!in_mst[n->to] && n->weight<key_of[n->to])
                { key_of[n->to]=n->weight;
                  parent_of[n->to]=u; }
    }
    *total_out=total;
    return mst_len;
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Prim's code (Java) — part 1/2

static int primMst(Graph g, int start,
                    Edge[] mstOut, int[] totalOut) {
    for (int v=0;v<g.vertexCount;v++)
        { keyOf[v]=INF; inMst[v]=false; parentOf[v]=-1; }
    keyOf[start]=0;
    int mstLen=0, total=0;
    for (int count=0;count<g.vertexCount;count++) {
        int u=minKeyVertex(g.vertexCount);
        if (u==-1 || keyOf[u]==INF) break;
        inMst[u]=true;
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Prim's code (Java) — part 2/2

        if (parentOf[u]!=-1) {
            mstOut[mstLen]=new Edge();
            mstOut[mstLen].a=parentOf[u];
            mstOut[mstLen].b=u;
            mstOut[mstLen].w=keyOf[u];
            mstLen++; total+=keyOf[u];
        }
        for (AdjNode n=g.adj[u]; n!=null; n=n.next)
            if (!inMst[n.to] && n.weight<keyOf[n.to])
                { keyOf[n.to]=n.weight; parentOf[n.to]=u; }
    }
    totalOut[0]=total;
    return mstLen;
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Prim's MST

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Real output: Prim's MST

-- normal: 7 vertices, 10 edges, starts at A --
MST edges: A-C:2 C-B:1 B-D:5 D-E:2 E-F:3 E-G:7
total weight = 20

-- edge: 2 components, starts at A -- F..J never reached --
MST edges: A-B:2 B-C:4 C-D:1 D-E:3
total weight = 10
unreached: F G H I J
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Complexity table

Algorithm Time Note
Kruskal O(E log E) sort dominates
Prim (array) O(V^2) matches Dijkstra's shape
Prim (heap) O(E log V) better on dense graphs
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Mini question

Could Prim ever pick a more expensive edge than Kruskal, on the same graph?

(answer: no — see next slide)

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Answer

No. Both are provably optimal (cut property).

Every MST of a graph has the same total weight — they can differ only in which edges they pick, when weights tie.

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

5. Single-Source Shortest Paths

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

A question to start

A road network, weighted by distance. Starting from one city,

what is the cheapest way to reach every other city?

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

A short history

  • Edsger Dijkstra, 1956 (published 1959)
  • A 20-minute exercise to demo a new computer
  • Still the standard answer when every weight is non-negative
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Dijkstra's idea

  • dist[v] = cheapest total path found so far
  • Pick the not-yet-finished vertex with smallest dist
  • Once picked: final, can never shrink again
  • Only true because no edge weight is negative
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Why negative weights break it

A vertex popped "final" early could later be beaten by a path through a very negative edge — discovered after it was already finalised.

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Dijkstra's code (C) — part 1/2

void dijkstra(Graph *g, int start) {
    for (int v=0;v<g->vertex_count;v++)
        { dist_of[v]=INF; done[v]=0; parent_of[v]=-1; }
    dist_of[start]=0;
    for (int count=0;count<g->vertex_count;count++) {
        int u=min_dist_vertex(g->vertex_count);
        if (u==-1 || dist_of[u]==INF) break;
        done[u]=1;
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Dijkstra's code (C) — part 2/2

        for (AdjNode *n=g->adj[u]; n; n=n->next) {
            int cand=dist_of[u]+n->weight;
            if (!done[n->to] && cand<dist_of[n->to])
                { dist_of[n->to]=cand; parent_of[n->to]=u; }
        }
    }
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Dijkstra's code (Java) — part 1/2

static void dijkstra(Graph g, int start) {
    for (int v=0;v<g.vertexCount;v++)
        { distOf[v]=INF; done[v]=false; parentOf[v]=-1; }
    distOf[start]=0;
    for (int count=0;count<g.vertexCount;count++) {
        int u=minDistVertex(g.vertexCount);
        if (u==-1 || distOf[u]==INF) break;
        done[u]=true;
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Dijkstra's code (Java) — part 2/2

        for (AdjNode n=g.adj[u]; n!=null; n=n.next) {
            int cand=distOf[u]+n.weight;
            if (!done[n.to] && cand<distOf[n.to])
                { distOf[n.to]=cand; parentOf[n.to]=u; }
        }
    }
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Dijkstra's shortest path

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Real output: Dijkstra

-- normal: 8 vertices, 10 edges, starts at A --
distances: A=0 B=3 C=2 D=8 E=10 F=13 G=17

-- edge: F..J never reachable via the directed edges --
distances: A=0 B=2 C=5 D=6 E=9 F=inf G=inf H=inf I=inf J=inf
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Bellman-Ford: negative weights OK

  • Bellman & Ford, late 1950s
  • Give up "pop the minimum" entirely
  • Relax every edge, fixed order, up to V - 1 rounds
  • A V-th round that still improves = a negative cycle
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Bellman-Ford's code (C) — part 1/2

int bellman_ford(Graph *g, int start) {
    for (int v=0;v<g->vertex_count;v++)
        { dist_of[v]=INF; parent_of[v]=-1; }
    dist_of[start]=0;
    for (int p=1;p<=g->vertex_count-1;p++) {
        int changed=0;
        for (int u=0;u<g->vertex_count;u++) {
            if (dist_of[u]==INF) continue;
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Bellman-Ford's code (C) — part 2/2

            for (AdjNode *n=g->adj[u]; n; n=n->next) {
                int cand=dist_of[u]+n->weight;
                if (cand<dist_of[n->to])
                    { dist_of[n->to]=cand;
                      parent_of[n->to]=u; changed=1; }
            }
        }
        if (!changed) break;
    }
    /* one more pass detects a negative cycle */
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Bellman-Ford's code (Java) — part 1/2

static boolean bellmanFord(Graph g, int start) {
    for (int v=0;v<g.vertexCount;v++)
        { distOf[v]=INF; parentOf[v]=-1; }
    distOf[start]=0;
    for (int pass=1;pass<=g.vertexCount-1;pass++) {
        boolean changed=false;
        for (int u=0;u<g.vertexCount;u++) {
            if (distOf[u]==INF) continue;
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Bellman-Ford's code (Java) — part 2/2

            for (AdjNode n=g.adj[u]; n!=null; n=n.next) {
                int cand=distOf[u]+n.weight;
                if (cand<distOf[n.to])
                    { distOf[n.to]=cand;
                      parentOf[n.to]=u; changed=true; }
            }
        }
        if (!changed) break;
    }
    /* one more pass detects a negative cycle */
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Bellman-Ford shortest path

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Required edge case: negative cycle

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Real output: Bellman-Ford

-- normal: 7 vertices, all positive, starts at A --
distances: A=0 B=3 C=2 D=8 E=10 F=13 G=17
no negative cycle

-- edge: A-B-C-A is a negative cycle (total -1) --
distances: A=-4 B=-2 C=0 D=0 E=1
negative cycle detected
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Complexity table

Algorithm Time Handles negatives?
Dijkstra O(V^2) No
Bellman-Ford O(V*E) Yes
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Mini question

Why exactly V - 1 rounds for Bellman-Ford, not V or V/2?

(answer on the next slide)

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Answer

A shortest path (no negative cycle) never repeats a vertex — at most V - 1 edges.

Each round extends every path's "confirmed" prefix by one edge. V - 1 rounds confirm the longest possible shortest path.

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

6. All-Pairs Shortest Paths

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

A question to start

A flight-booking system needs the cheapest fare between every pair of ~20 cities, at once.

Running Dijkstra 20 times works — is there a way to share the work?

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

A short history

  • Robert Floyd & Stephen Warshall, both 1962
  • Independent, closely related matrix algorithms
  • Combined algorithm carries both names
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

The idea

  • An N x N matrix dist[i][j]
  • For every vertex k: is i -> k -> j shorter than dist[i][j]?
  • Try every vertex as an intermediate stop
  • Update in place — safe, since dist[i][k]/dist[k][j] never change mid-pass
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Floyd-Warshall's code (C)

void floyd_warshall(int vertex_cnt) {
    for (int k=0;k<vertex_cnt;k++) {
        for (int i=0;i<vertex_cnt;i++) {
            for (int j=0;j<vertex_cnt;j++) {
                if (dist[i][k]==INF || dist[k][j]==INF)
                    continue;
                int through=dist[i][k]+dist[k][j];
                if (through<dist[i][j])
                    dist[i][j]=through;
            }
        }
    }
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Floyd-Warshall's code (Java)

static void floydWarshall(int vertexCnt) {
    for (int k=0;k<vertexCnt;k++) {
        for (int i=0;i<vertexCnt;i++) {
            for (int j=0;j<vertexCnt;j++) {
                if (dist[i][k]==INF || dist[k][j]==INF)
                    continue;
                int through=dist[i][k]+dist[k][j];
                if (through<dist[i][j])
                    dist[i][j]=through;
            }
        }
    }
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Floyd-Warshall: the matrix fills in

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Real output: Floyd-Warshall

-- normal: 5 vertices, negative edges but no negative cycle --
      A   B   C   E   D
  A   0   1  -3  -4   2
  B   3   0  -4  -2   1
  C   7   4   0   2   5
no negative cycle

-- edge: A-B-C-A is a negative cycle --
negative cycle at: A B C
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Complexity & mistake

  • O(V^3) time, O(V^2) space
  • Practical for a few hundred vertices, not more
  • Mistake: k as the innermost loop silently computes garbage
  • Mistake: forgetting the == INF guard → integer overflow
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Mini question

Bellman-Ford finds negative cycles reachable from one start. Floyd-Warshall's diagonal check finds them differently — how?

(answer on the next slide)

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Answer

Any dist[v][v] that drops below zero means: a path leaves v and comes back cheaper than staying put.

Since Floyd-Warshall computes every pair, this check runs for every vertex at once — no separate start vertex needed.

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

7. Strongly Connected Components

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

A question to start

Which groups of vertices can reach each other and get back, respecting edge direction?

Web pages linking in a cycle. Mutually-recursive functions.

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Kosaraju's idea

  • Sergei Kosaraju, ~1978 (credited via Micali & Vazirani, 1981)
  • Phase 1: DFS, record every vertex's finish time
  • Phase 2: DFS the transpose (edges reversed)
  • Visit roots in decreasing finish-time order
  • Each DFS tree in phase 2 = one SCC
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Kosaraju's code (C)

void dfs1(int u) {            /* phase 1 */
    visited[u]=1;
    for (AdjNode *n=cur_g->adj[u]; n; n=n->next)
        if (!visited[n->to]) dfs1(n->to);
    finish[finish_len++]=u;
}

void dfs2(int u, int id) {    /* phase 2, on adjT */
    visited[u]=1; comp_of[u]=id;
    for (AdjNode *n=cur_g->adjT[u]; n; n=n->next)
        if (!visited[n->to]) dfs2(n->to, id);
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Kosaraju's code (Java)

static void dfs1(int u) {            // phase 1
    visited[u]=1;
    for (AdjNode n=curG.adj[u]; n!=null; n=n.next)
        if (visited[n.to]==0) dfs1(n.to);
    finish[finishLen]=u; finishLen++;
}

static void dfs2(int u, int id) {    // phase 2, on adjT
    visited[u]=1; compOf[u]=id;
    for (AdjNode n=curG.adjT[u]; n!=null; n=n.next)
        if (visited[n.to]==0) dfs2(n.to, id);
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Strongly connected components

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Edge case: one big cycle

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Real output: strongly connected components

-- normal: 8 vertices, 2 cyclic components + 2 singletons --
4 components:
  A B C
  D E F
  G
  H

-- edge: everything is one big cycle --
1 component:
  A B C D E F G H
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Complexity & mistake

  • O(V + E) — two full DFS passes
  • Mistake: running phase 2 in the same order as phase 1
  • Must be reversed — the single most common bug here
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Mini question

On a DAG (no cycles at all), how many strongly connected components does Kosaraju's algorithm find?

(answer on the next slide)

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Answer

Exactly V — one per vertex.

With no cycle anywhere, no vertex can return to itself through any path, so every component is a singleton. This is the last edge case in this week's SCC animation.

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

8. Bipartite Graphs

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

A question to start

Schedule exams so no student has two at once. Courses sharing a student → an edge.

Can this graph be 2-coloured — the simplest possible timetable?

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

BFS with two colours

  • Colour the start 0; every neighbour the opposite colour
  • A same-coloured neighbour already queued? Conflict — not bipartite
  • One BFS per component (like Week 5's components loop)
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

The odd-cycle equivalence

A graph is bipartite if and only if it has no odd-length cycle.

An even cycle alternates colours perfectly. An odd one cannot close up consistently.

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Bipartite check code (C) — part 1/2

int is_bipartite(Graph *g) {
    for (int i=0;i<g->vertex_count;i++) color_of[i]=-1;
    for (int s=0;s<g->vertex_count;s++) {
        if (color_of[s]!=-1) continue;
        color_of[s]=0; front=rear=0; enqueue(s);
        while (front<rear) {
            int u=dequeue();
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Bipartite check code (C) — part 2/2

            for (AdjNode *n=g->adj[u]; n; n=n->next) {
                if (color_of[n->to]==-1)
                    { color_of[n->to]=1-color_of[u];
                      enqueue(n->to); }
                else if (color_of[n->to]==color_of[u])
                    return 0;
            }
        }
    }
    return 1;
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Bipartite check code (Java) — part 1/2

static boolean isBipartite(Graph g) {
    for (int i=0;i<g.vertexCount;i++) colorOf[i]=-1;
    for (int s=0;s<g.vertexCount;s++) {
        if (colorOf[s]!=-1) continue;
        colorOf[s]=0; front=rear=0; enqueue(s);
        while (front<rear) {
            int u=dequeue();
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Bipartite check code (Java) — part 2/2

            for (AdjNode n=g.adj[u]; n!=null; n=n.next) {
                if (colorOf[n.to]==-1)
                    { colorOf[n.to]=1-colorOf[u];
                      enqueue(n.to); }
                else if (colorOf[n.to]==colorOf[u])
                    return false;
            }
        }
    }
    return true;
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Bipartite graph check

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Edge case: an odd cycle

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Real output: bipartite check

-- normal: an even cycle plus 2 safe diagonals --
colors: A=0 B=1 C=0 D=1 E=0 F=1 G=0 H=1
bipartite

-- edge: A-B-C-D-E-A is a 5-cycle (odd) --
colors: A=0 B=1 C=0 D=-1 E=1 F=1 G=-1 H=-1
NOT bipartite
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Complexity & mistake

  • O(V + E) — one BFS
  • Mistake: not handling disconnected graphs
  • An odd cycle isolated in a second component is invisible without a per-component loop
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Mini question

Why does a conflict edge ("same colour as its neighbour") always exist within one BFS layer or between two adjacent layers — never skip a layer?

(answer on the next slide)

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Answer

BFS colours strictly by distance parity from the source — even distance gets colour 0, odd gets colour 1.

Any edge connects vertices whose BFS distances differ by exactly 0 or 1 (never 2+, or it wouldn't be a direct edge) — so a conflict can only appear exactly there.

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

9. Maximum Flow

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

A question to start

A water network: source, destination, pipes with capacities.

What is the largest total flow the network can deliver at once?

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

A short history

  • Ford & Fulkerson, 1956 — the general method
  • Edmonds & Karp, 1972 — always use the shortest augmenting path
  • Proved: this choice guarantees polynomial time
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

The idea

  • Find any augmenting path, s to t, with spare capacity
  • Push the bottleneck (smallest capacity on the path)
  • Pushing forward opens a reverse edge — a later path can "undo"
  • The graph of "still usable" is the residual graph
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Max-flow min-cut

Max flow equals the cheapest cut — the smallest total capacity separating s from t.

No augmenting path left = BFS's reachable set from s is that cut.

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Edmonds-Karp code (C) — part 1/2

int edmonds_karp(int vertex_cnt, int s, int t) {
    int max_flow=0;
    while (bfs_augmenting_path(vertex_cnt, s, t)) {
        int bottleneck=INF;
        for (int v=t; v!=s; v=parent_of[v])
            if (cap_of[parent_of[v]][v]<bottleneck)
                bottleneck=cap_of[parent_of[v]][v];
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Edmonds-Karp code (C) — part 2/2

        for (int v=t; v!=s; v=parent_of[v]) {
            int u=parent_of[v];
            cap_of[u][v]-=bottleneck;
            cap_of[v][u]+=bottleneck;
        }
        max_flow+=bottleneck;
    }
    return max_flow;
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Edmonds-Karp code (Java) — part 1/2

static int edmondsKarp(int vertexCnt, int s, int t) {
    int maxFlow=0;
    while (bfsAugmentingPath(vertexCnt, s, t)) {
        int bottleneck=INF;
        for (int v=t; v!=s; v=parentOf[v]) {
            int u=parentOf[v];
            if (capOf[u][v]<bottleneck)
                bottleneck=capOf[u][v];
        }
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Edmonds-Karp code (Java) — part 2/2

        for (int v=t; v!=s; v=parentOf[v]) {
            int u=parentOf[v];
            capOf[u][v]-=bottleneck;
            capOf[v][u]+=bottleneck;
        }
        maxFlow+=bottleneck;
    }
    return maxFlow;
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Edmonds-Karp maximum flow

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Real output: Edmonds-Karp

-- normal: 6 vertices, 10 edges, A to F --
max flow from A to F = 9

-- edge: A and J are in two separate components --
max flow from A to J = 0
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Complexity & mistake

  • O(V * E^2) for Edmonds-Karp specifically
  • Mistake: forgetting the reverse edge update
  • Without it: plain Ford-Fulkerson, can get stuck short of optimal
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Mini question

Section 3's union-find could answer "0 flow, s and t disconnected" instantly. Why does this section still run a full BFS first?

(answer on the next slide)

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Answer

Union-find only knows reachability, not capacity.

Even when s and t ARE connected, the actual max flow depends on the bottleneck capacities along the way — something union-find's parent pointers never recorded.

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

10. Backtracking

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

A question to start

Colour a map so no two neighbours share a colour, with as few colours as possible.

No known formula. How do you search systematically?

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

The idea: try, recurse, undo

  • Extend a partial solution by one decision
  • Still consistent? Recurse and keep extending
  • Inconsistent, or every extension fails? Undo and try the next option
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Why graph colouring, not Hamiltonian path?

Colouring reuses Section 8's exact color[] row and neighbour-conflict check.

A Hamiltonian path needs an entirely new "path so far" convention — for comparatively little extra insight.

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Backtracking code (C)

int color_graph(int v, int k) {
    if (v==cur_g->vertex_count) return 1;
    for (int c=1;c<=k;c++) {
        if (safe(v,c)) {
            color_of[v]=c;
            if (color_graph(v+1,k)) return 1;
            color_of[v]=0;   /* backtrack */
        }
    }
    return 0;
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Backtracking code (Java)

static boolean colorGraph(int v, int k) {
    if (v==curG.vertexCount) return true;
    for (int c=1;c<=k;c++) {
        if (safe(v,c)) {
            colorOf[v]=c;
            if (colorGraph(v+1,k)) return true;
            colorOf[v]=0;   // backtrack
        }
    }
    return false;
}
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Backtracking: graph colouring

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Required edge case: K4, unsolvable

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Real output: backtracking graph colouring

-- normal: 6 vertices, 10 edges, k=3 --
colouring: A=1 B=2 C=3 D=1 E=2 F=3

-- edge: K4 is UNSOLVABLE with k=3 --
no valid colouring with k=3
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Complexity & mistake

  • Worst case O(k^V) — a last-resort technique
  • safe() prunes huge swaths early — why it's usable at all
  • Mistake: forgetting the undo step corrupts later branches
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Mini question

K4 needs 4 colours. How many vertices does the algorithm actually try to colour before reporting "unsolvable" with k=3?

(answer on the next slide)

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Answer

All of them, every time it backtracks past vertex 0 — but the failure is detected at vertex 3, the 4th vertex of K4, since the first 3 already used all 3 available colours between them.

safe() then rejects every colour for vertex 3, forcing a chain of undos all the way back to the start.

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

How each program was checked

  • Every C program compiles with -Wall -Wextra -Werror
  • Every Java program compiles with -Xlint:all -Werror
  • C and Java output diffed byte-identical, same scenarios
  • Every unit test file also rebuilt under AddressSanitizer
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

One sentence per algorithm

  • Kahn / DFS topo-sort: order respecting every "before" rule
  • Cycle detection: which vertices, not just whether
  • Union-find: "same group?" in near-constant time
  • Kruskal / Prim: cheapest way to connect everything
  • Dijkstra / Bellman-Ford: cheapest path from one start
  • Floyd-Warshall: cheapest path between every pair at once
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

One sentence per algorithm (cont.)

  • Kosaraju SCC: mutual reachability, directed
  • Bipartite check: can this be split into exactly two teams?
  • Edmonds-Karp: the largest flow a network can carry
  • Backtracking: try, recurse, undo — for problems with no formula
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Summary table (1/3)

Problem Algorithm Time
Order Kahn / DFS topo-sort O(V+E)
Cycle? 3-colour DFS O(V+E)
Groups Union-find ~O(1) amortised
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Summary table (2/3)

Problem Algorithm Time
Cheapest connect Kruskal / Prim O(E log E) / O(V^2)
Cheapest path Dijkstra / Bellman-Ford O(V^2) / O(V*E)
All-pairs paths Floyd-Warshall O(V^3)
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Summary table (3/3)

Problem Algorithm Time
Mutual reach Kosaraju SCC O(V+E)
2-team split Bipartite check O(V+E)
Max flow Edmonds-Karp O(V*E^2)
No formula Backtracking O(k^V) worst case
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Exercises (pick a few)

  • Trace Kahn's algorithm by hand on a 5-edge DAG
  • Build a graph with a negative edge but no negative cycle
  • Modify SCC to flag trivial (single-vertex) components
  • Prove every tree is bipartite
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Self-check: 3 quick questions

  1. Why does Dijkstra fail on a negative edge?
  2. What's the ONE new idea Kosaraju adds over topological-sort DFS?
  3. What does a reverse residual edge let a later augmenting path do?
RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Looking ahead

Week 10: Advanced Tree Structures

AVL trees, red-black trees, B-trees — the self-balancing machinery that keeps O(log n) from collapsing to O(n) on unlucky insertions.

RTEU Computer Engineering · Fall 2026–2027
CEN207 Data Structures · Week 9

Questions?

CEN207 Data Structures · Week 9 · Graph Algorithms

RTEU Computer Engineering · Fall 2026–2027

Speaker note: Welcome back after the midterm week. This week extends every Week 5 graph tool with order, weight, and cycle awareness, and closes with backtracking.

Speaker note: Eleven algorithms, ten sections — some sections pair two algorithms that solve the same problem two ways.

Speaker note: Every algorithm this week extends BFS or DFS with one or two extra arrays. Nothing here replaces Week 5 — it builds on it directly.

Speaker note: Kruskal, Prim, Dijkstra, Bellman-Ford, Floyd-Warshall, Edmonds-Karp all need weights. The other five stay unweighted.

Speaker note: Nothing about the graph representation changes -- only what we compute over it.

Speaker note: This is exactly the build-system / package-manager dependency problem.

Speaker note: Kahn's paper is literally titled "Topological sorting of large networks".

Speaker note: The queue holds every vertex currently eligible to be placed, all at once.

Speaker note: Count in-degrees, then seed the queue with every vertex that already has in-degree 0.

Speaker note: Relax every dequeued vertex's neighbours, enqueueing any that newly reach in-degree 0.

Speaker note: Identical shape to the C version so far.

Speaker note: Same shape as the C version, line for line -- that parity is why the code panel's line numbers stay meaningful in both languages.

Speaker note: Watch the queue and the order row fill together. Try the cycle edge case next.

Speaker note: The queue empties early — the leftover vertices are locked in a cycle with each other.

Speaker note: Real captured output from the compiled C program, byte-identical to the Java program's output.

Speaker note: A back edge to a still-open (grey) vertex means a cycle — caught for free.

Speaker note: The finish[] array fills bottom-up; the caller reads it back to front for the topological order.

Speaker note: One dfs_visit call per unvisited vertex -- this is what covers a disconnected DAG.

Speaker note: hasCycle is set the moment a back edge is seen, but the loop keeps going to finish every vertex.

Speaker note: Same shape as the C driver, line for line.

Speaker note: Same graph as Kahn's — compare the two valid orders.

Speaker note: Two correct algorithms on the same DAG can (and do) disagree on the exact order.

Speaker note: Give the audience 20 seconds.

Speaker note: This is also why more than one valid order usually exists.

Speaker note: Kahn's algorithm can't answer this at all — only "some vertices never reach 0".

Speaker note: We can read the cycle directly off the path array.

Speaker note: A white neighbour recurses; a grey neighbour is an ancestor -- the cycle-found branch continues next slide.

Speaker note: The extraction loop walks back from the top of the path to the grey ancestor.

Speaker note: Same shape as the C version so far.

Speaker note: onPath[] is a plain array used as a stack -- push on entry, pop on the way back out.

Speaker note: Watch the cycle vertices turn red and get boxed below the graph.

Speaker note: Every vertex turns black, no back edge is ever found.

Speaker note: A 2-vertex cycle is the smallest possible directed cycle -- a single edge can never be one.

Speaker note: This is the same trap as Section 1's forward/cross edges.

Speaker note: This trade-off — a bit more bookkeeping for a lot more information — recurs all week.

Speaker note: We need a structure built specifically for "same group?" queries.

Speaker note: Each group is a tiny tree; the root IS the group's identity.

Speaker note: α is the inverse Ackermann function — under 5 for any n you could ever build.

Speaker note: The second while loop is the path compression step -- it re-points every visited node at the root.

Speaker note: Merging by ROOT, never by the raw a/b arguments, is the one rule that must never be broken here.

Speaker note: Identical shape to the C version -- union-find translates almost line for line between languages.

Speaker note: Same rank-comparison ladder as the C version.

Speaker note: "already the same set" is not an error -- union() on an already-merged pair is always safe, a no-op.

Speaker note: Watch a genuine depth-2 chain flatten to depth 1 in one find() call.

Speaker note: Merging raw arguments can create a node with two parents.

Speaker note: Some textbooks use "union by size" exclusively — both are correct, this course picks rank for the height argument.

Speaker note: Not every pair needs a direct line — just everyone reachable from everyone.

Speaker note: The cheapest edge crossing any partition of the vertices must belong to some MST.

Speaker note: Kruskal doesn't care where the tree "is" — it just avoids cycles globally.

Speaker note: This is the same "priority queue as a row" idea we'll reuse for Dijkstra.

Speaker note: A fresh union-find, then one global sort by weight -- exactly as described a slide ago.

Speaker note: find and union_sets are exactly Section 3's union-find, unchanged.

Speaker note: Java's Comparator chain replaces C's qsort + comparator function -- same tie-break, different syntax.

Speaker note: Same loop shape as the C version's second half.

Speaker note: The sorted-edges row and the parent[] row grow together.

Speaker note: Two components in, two trees out — no error, just a forest.

Speaker note: Two components in, two separate trees out, added together into one edge list.

Speaker note: key_of[] IS the priority-queue row shown below the graph in the animation.

Speaker note: Record the edge that just brought u into the tree, then relax u's neighbours.

Speaker note: Same shape as the C version so far.

Speaker note: Java allocates a new Edge object per MST edge; C fills a pre-allocated array slot -- the only real difference.

Speaker note: Same "normal" graph as Kruskal's — compare the two MSTs: same total weight.

Speaker note: total weight = 20, matching Kruskal's on the same normal graph -- a nice cross-check to show live.

Speaker note: We use the array version so the priority queue is a visible, simple row.

Speaker note: Total weight is invariant; the specific edge set is not, under ties.

Speaker note: Not "fewest edges" (Week 5's BFS) — cheapest total weight.

Speaker note: Dijkstra later said he designed it without pencil and paper, on a terrace in Amsterdam.

Speaker note: Prim's algorithm with one change: "cheapest edge in" becomes "cheapest path so far".

Speaker note: This is exactly why Dijkstra refuses negative input in our program.

Speaker note: min_dist_vertex is the "priority queue" step, shown as a row in the animation.

Speaker note: Relax every not-yet-done neighbour of the just-finalised vertex u.

Speaker note: Same shape as the C version so far.

Speaker note: minDistVertex is a small linear scan -- the Java and C versions are effectively identical.

Speaker note: The priority queue row is a plain sorted array, not a heap.

Speaker note: "inf" prints exactly when a vertex was never reached -- the program's own sentinel, not a crash.

Speaker note: V-1 rounds are exactly enough for the longest possible shortest path to propagate.

Speaker note: Up to V-1 rounds, skipping any vertex not yet reached at all.

Speaker note: The early-exit "if (!changed) break" is a common, correct optimisation.

Speaker note: Same shape as the C version so far.

Speaker note: boolean replaces C's int flag -- otherwise line-for-line identical.

Speaker note: Watch the round counter and the detection round at the end.

Speaker note: A-B-C-A sums to -1. The detection round finds a still-relaxable edge.

Speaker note: Same starting graph shape as Dijkstra's -- compare the two "distances:" lines side by side.

Speaker note: Bellman-Ford's price for tolerating negatives is a much slower worst case.

Speaker note: Repeating a vertex means looping through non-negative extra weight — never an improvement.

Speaker note: 20 * O(V^2) vs. one shared O(V^3) computation.

Speaker note: Warshall's was for reachability; Floyd's for shortest distances.

Speaker note: This in-place safety is a rare, pleasant simplification.

Speaker note: k must be the OUTERMOST loop — that's the whole correctness argument.

Speaker note: dist is a Java 2-D array here, vs. C's dist[i][k] on a fixed-size static array -- same access pattern.

Speaker note: One step per intermediate vertex k — not per (i,j) pair, or this would be far too many steps.

Speaker note: A negative diagonal entry (dist[A][A] < 0) is exactly what flags a negative cycle through that vertex.

Speaker note: INF + INF can wrap around to a large negative number without the guard.

Speaker note: This is a nice payoff of solving the harder, more general problem: some questions become simpler, not harder.

Speaker note: Week 5's connected components ignore direction entirely — this is the directed version.

Speaker note: Chosen over Tarjan's one-pass algorithm because it reuses Section 1's exact DFS + finish time.

Speaker note: dfs1 and dfs2 look almost identical — the only difference is adj vs adjT.

Speaker note: adjT is the transpose graph, built once alongside adj when the Graph is constructed.

Speaker note: Watch phase 1's finish order, then phase 2's transpose-graph DFS trees.

Speaker note: When everything can reach everything, there is exactly one SCC.

Speaker note: A single vertex with no cycle through it is still a valid SCC -- just a component of size one.

Speaker note: Forgetting to reset visited[] between the two phases is the second most common bug.

Speaker note: It's a useful sanity check: SCC count == vertex count if and only if the graph is a DAG.

Speaker note: A much faster question than general graph colouring (Section 10).

Speaker note: This equivalence is provable directly from the BFS coloring argument.

Speaker note: The outer for-s loop is what makes this correct on a disconnected graph -- reused from components.

Speaker note: The colour assignment happens at enqueue time, not dequeue time — deliberately.

Speaker note: Same shape as the C version so far.

Speaker note: The outer for-s loop is what makes this correct on a disconnected graph -- Section 3's components idea, reused.

Speaker note: Watch a conflicting edge flash red the moment BFS reaches it.

Speaker note: The function returns immediately — later vertices stay uncoloured, and that's expected.

Speaker note: color -1 means "never reached by BFS" -- the search stopped the instant it found the conflict.

Speaker note: A tree is always bipartite (no cycles at all) — a useful sanity check, not a shortcut.

Speaker note: This is the same distance-parity idea that proves the odd-cycle equivalence two slides back.

Speaker note: Ford-Fulkerson with an arbitrary path choice can be pathologically slow.

Speaker note: The reverse edge is what lets Edmonds-Karp beat a naive greedy approach.

Speaker note: This is why running out of augmenting paths proves optimality, not just termination.

Speaker note: First walk back along parent_of[] from t to s: find the smallest residual capacity on the path.

Speaker note: Second walk: apply the bottleneck, opening a reverse residual edge as it goes.

Speaker note: Same two-walk shape as the C version.

Speaker note: capOf is a plain int[][] matrix in Java, matching C's 2-D array exactly.

Speaker note: Every edge shows flow/capacity; the residual row lists every positive residual pair.

Speaker note: Max flow 0 is a perfectly valid answer -- it's what "no augmenting path exists at all" looks like.

Speaker note: DFS instead of BFS is still correct but loses the polynomial-time guarantee.

Speaker note: A nice callback that also previews why max-flow is strictly harder than plain connectivity.

Speaker note: N-queens, seating charts, and Hamiltonian paths all share this shape.

Speaker note: "Backtracking" refers specifically to the undo step.

Speaker note: Four lines carry the whole idea: try, recurse, undo, and the safety check does the pruning.

Speaker note: safe(v,c) is a short neighbour scan, the same shape as Section 8's bipartite conflict check.

Speaker note: A rejected colour flashes red; an undone colour clears back to empty.

Speaker note: Every combination is tried and found unsafe — proven failure, not a lucky success.

Speaker note: "no valid colouring" only prints after every branch has been tried and undone -- a proven negative.

Speaker note: This is the whole reason backtracking works despite the exponential bound.

Speaker note: Worth tracing live on the animation slide if time allows — watching the full backtrack chain is the point of this algorithm.

Speaker note: This is the run_tests.py pipeline used for every program this week, not just a few.

Speaker note: First half of the week, one line each.

Speaker note: Second half. Together, eleven algorithms, ten problems (topo-sort has two solutions).

Speaker note: This table mirrors the note's summary table exactly, split across three slides to fit.

Speaker note: Four rows here since this closes out the list -- still comfortably within the slide.

Speaker note: Full ten-exercise list is in this week's notes.

Speaker note: Full ten-question quiz, with answers, is in this week's notes.

Speaker note: This week mostly worked on arrays and adjacency lists — Week 10 returns to balanced trees.

Speaker note: Open floor for questions before the self-check quiz.