Cairn
algorithms · greedy · O(V+E)

back to Greedy

Greedy Coloring

Walk a graph's vertices in some fixed order. For each one, look at whichever of its neighbors are already colored, and assign the smallest color number none of them hold. That's the entire rule — no lookahead, no backtracking, one pass, done. It's the ninth entry filed under Greedy, and the first one over a graph rather than an interval set, a frequency table, or a capacity. Graph Coloring already covers this same question — assign colors so no edge joins two same-colored vertices — with a backtracking search that finds the true minimum, at exponential worst-case cost and no guarantee of finishing quickly. This page is the other end of that trade: always fast, one pass, but with no promise of using anywhere near the fewest colors possible.

Try it

The graph below is a crown graph: two groups of four vertices, a1–a4 and b1–b4, with an edge between ai and bj for every pair except where i = j. No edge ever runs within a group, so the whole graph is two-colorable in principle — but greedy doesn't know that, and whether it finds a 2-coloring depends entirely on which order you feed it. Pick a vertex order and a neighbor-checking rule, then press Step or Run.

Press Step or Run.

Why it works

Greedy coloring's one guarantee has nothing to do with how few colors it uses — it's a bound on how many it could ever be forced to use. When vertex v is colored, at most degree(v) neighbors are already colored, and each contributes at most one excluded color. So among colors 0 through Δ (that's Δ+1 colors total, where Δ is the graph's maximum degree), at least one is never excluded for any vertex, no matter the order. Every vertex on the demo's graph has degree 3 (each ai touches exactly the three bj with j ≠ i, and symmetrically for each bj), so Δ+1 = 4 — and a sweep of 5,000 random vertex orders on this exact graph, using the correct rule, never once needed a fifth color, confirming the bound holds for every order, not just the two offered above.

What the bound does not promise is closeness to the true minimum. This graph's real chromatic number is 2 — group a versus group b is itself a valid 2-coloring, since every edge runs between the groups and none within one, confirmed here independently by a plain two-coloring breadth-first search rather than just asserted. Feed the vertices in grouped order and greedy finds that exact 2-coloring: every a vertex gets colored before any b vertex sees a colored neighbor at all, so all four a's take color 0, then all four b's take color 1. Feed the identical graph in interleaved order instead and greedy uses all 4 colors — a1=0, b1=0, a2=1, b2=1, a3=2, b3=2, a4=3, b4=3 — hitting the Δ+1 worst case exactly, on a graph that never needed more than 2. Same graph, same rule, same code; only the order changed.

Reference implementation

function greedyColor(adjacency, order) {
  const n = adjacency.length;
  const color = new Array(n).fill(-1);

  for (const v of order) {
    const excluded = new Set();
    for (const u of adjacency[v]) {
      if (color[u] !== -1) excluded.add(color[u]);
    }
    let c = 0;
    while (excluded.has(c)) c++;
    color[v] = c;
  }
  return color;
}

No sorting, no priority queue, no revisiting a vertex once it's colored — the entire algorithm is one pass over order, checking each edge once from whichever endpoint gets colored second. That simplicity is exactly why the bound above is the only guarantee on offer: there is no step anywhere in this loop that looks at the graph's global structure, so nothing here can notice that groups a and b would have made a clean 2-coloring if only they'd been visited in the right order.

Pitfalls

Vertex order changes how many colors get used — sometimes optimally, sometimes hitting the worst case exactly — without changing a single line of the algorithm. The demo above makes this concrete rather than asserting it: grouped order finds the true 2-color optimum, interleaved order forces all 4 of the colors the Δ+1 bound allows, on the identical graph, using the identical correct rule. Unlike Set Cover's greedy approximation, which comes with a proven O(ln n) ceiling on how far off it can land relative to the true optimum regardless of input, greedy coloring has no such ceiling at all — the gap between what it uses and the true chromatic number can be made to grow without bound. Stretching this same crown-graph construction to n vertices per group under the interleaved order forces exactly n colors every time (checked directly for n = 2, 3, 4, 5, 8, 10, and 20, matching Δ+1 = n exactly at every size), while the true chromatic number stays fixed at 2 forever — a gap that widens with no ceiling as the graph grows, not a fixed worst-case factor the way Set Cover's is.

Checking only the most recently colored neighbor, instead of every colored neighbor, can produce an outright invalid coloring — not just a wasteful one. Switch the demo's rule to check only the most recently colored neighbor on the unchanged interleaved order: vertex a3's real neighbors are b1, b2, and b4. By the time a3 is colored, both b1 (color 0) and b2 (color 1) are already colored — but this rule only looks at whichever of them was colored most recently, b2, and excludes only color 1. That leaves color 0 looking free, so a3 takes it — directly colliding with b1, which is also color 0 and genuinely adjacent. The demo's own independent end-of-run scan, which re-examines every edge for a same-color pair rather than trusting the coloring loop's own bookkeeping, flags this pair immediately; on this exact run it finds four such collisions, not just one. This isn't reliably broken, either, which is what makes it a real trap rather than an obviously-bad idea: the identical shortcut on the grouped order produces zero collisions, because every neighbor an already-colored vertex has at that point happens to share the same color anyway. Checked beyond these two hand-picked orders: across 5,000 random vertex orders on this graph, the shortcut produced at least one genuine collision in 1,264 of them (25.3%) — wrong often enough to matter, rare enough that a few lucky test orders could hide it.

Complexity

Time: O(V+E) — each vertex is visited once, and each edge is examined exactly once, from whichever of its two endpoints gets colored second (that's the one already-colored neighbor it can see at that moment). Space: O(V) for the color array; the per-vertex exclusion set never holds more than degree(v) entries, so O(Δ) at any one step, which is at most O(V). The broken most-recent-neighbor variant above costs no more or less — the bug is entirely in which colors it considers excluded, not in how much work it does.

See Choosing a Greedy Strategy for how this entry compares against the site's other nine Greedy entries — short version: this is the guide's first entry with no ratio bound at all, a step past even Set Cover's proven-but-imperfect guarantee. For the exact minimum this page's greedy rule doesn't promise, see Graph Coloring's backtracking search.