1. Problem and Motivation
Single-machine scheduling asks a deceptively small question: given a set of jobs, each with a processing time $p_i$ and possibly a deadline $d_i$ and a weight $w_i$, and exactly one machine that can run one job at a time, in what order should the jobs run? The order is a permutation of $n$ jobs, so brute force costs $O(n!)$ — completely impractical past a dozen jobs. Yet for many natural objectives, a single sorting rule, checkable in $O(n \log n)$, is provably optimal.
The catch is that the objective determines the rule. "Minimize the number of jobs that miss their deadline" wants one ordering. "Minimize the total weighted time customers wait for their job to finish" wants a different ordering. "Minimize the worst deadline miss" wants yet another. Confusing these rules — or assuming one greedy trick solves every scheduling objective — is the most common single-machine scheduling mistake. This lesson treats each objective as its own small theorem: state the rule, trace it by hand, prove it safe, then implement it.
2. Prerequisites
This lesson assumes you are comfortable with:
- Greedy exchange arguments — the proof pattern of showing that any optimal solution can be reshaped, one adjacent swap at a time, into the greedy solution without losing value. See Part 16: Activity Selection & the Exchange Argument for the pattern in its simplest form.
- Job Sequencing with deadlines and profits — choosing which jobs to run (not just their order) to maximize profit, where every job takes one unit of time. That problem is already fully worked out, including its $O(n^2)$ implementation and a note on an $O(n \log n)$ Union-Find optimization, in Part 16, Section 7: Job Sequencing with Deadlines and Profits. This lesson does not repeat it — every job here has an arbitrary processing time and (except in Job Sequencing) every job eventually runs.
- Earliest Deadline First's staying-ahead proof — Part 16 is being extended with a new Section 8: Staying-Ahead Arguments that proves EDF optimal for minimizing maximum lateness, using the full inductive "staying ahead" technique. Section 6 below covers the EDF algorithm and states its correctness conclusion; the formal proof lives there.
- Basic heap operations (insert, extract-max) and array sorting, both used throughout the implementations below.
3. A Concrete Example
Tracing Moore-Hodgson's algorithm by hand
Five jobs, already sorted by deadline, each takes one unit of processing time per unit listed (no preemption, all available at time 0):
| Job | Processing time $p$ | Deadline $d$ |
|---|---|---|
| A | 1 | 2 |
| B | 2 | 3 |
| C | 6 | 4 |
| D | 4 | 5 |
| E | 2 | 6 |
Process jobs in deadline order, keeping a running completion time of everything scheduled so far:
| Step | Add | Running time | Exceeds its deadline? | Action |
|---|---|---|---|---|
| 1 | A (p=1) | 1 | 1 ≤ 2, no | Keep A scheduled |
| 2 | B (p=2) | 3 | 3 ≤ 3, no | Keep A, B scheduled |
| 3 | C (p=6) | 9 | 9 > 4, yes | Largest $p$ among {A,B,C} is C (6) — remove C, mark late. Running time: 9−6=3 |
| 4 | D (p=4) | 7 | 7 > 5, yes | Largest $p$ among {A,B,D} is D (4) — remove D, mark late. Running time: 7−4=3 |
| 5 | E (p=2) | 5 | 5 ≤ 6, no | Keep A, B, E scheduled |
Result: on-time = {A, B, E}, late = {C, D}. Only 2 jobs are late. Checking every one of the $\binom{5}{4}=5$ possible 4-job subsets against its own earliest-deadline schedule shows none of them are feasible — so 3 on-time jobs really is the best possible, and Moore-Hodgson found it.
The trace shows the entire algorithm in miniature: sort by deadline, add jobs one at a time, and whenever the running completion time overshoots the deadline just added, evict the largest job seen so far — not necessarily the one that triggered the overflow.
4. Moore-Hodgson's Algorithm (Minimizing Late Jobs)
Given $n$ jobs with processing times $p_i$ and deadlines $d_i$ on one machine (no preemption, all available at time 0), find a schedule that minimizes the number of jobs that finish after their deadline. Unlike Job Sequencing, every job eventually runs — on time or late — there is no profit to skip for.
Plain-English Steps
- Sort all jobs by deadline, ascending.
- Maintain a running total
time(initially 0) and a max-heap of the processing times of jobs currently considered "scheduled." - For each job in deadline order: add it to the scheduled set (push onto the heap) and add its processing time to
time. - If
timenow exceeds the current job's deadline, pop the largest processing time from the heap, subtract it fromtime, and mark that job late. - After all jobs are processed, the heap holds exactly the on-time jobs (schedule them in deadline order); everything popped out along the way is late.
Correctness: an Exchange Argument
Two facts make the greedy eviction rule safe:
- Any violation forces at least one eviction. Once the running time exceeds the just-added job's deadline $d$, at least one job among those scheduled so far (all with deadline $\le d$, since jobs are processed in deadline order) must be dropped, or every remaining scheduled job's completion time is provably too late.
- Evicting the largest processing time is never worse than evicting anything else. Removing any single job from the scheduled set fixes the overflow (by definition of "one job over," since the schedule was feasible one job ago). Among all jobs whose removal fixes it, removing the one with the largest $p$ frees the most slack in the remaining schedule for the same cost of "one job lost" — so it can only make it easier, never harder, to keep every job added afterward on time. A standard interchange argument then shows: for any optimal solution that evicts a different job at this point, swapping its choice for the largest-$p$ job produces another optimal solution with at least as much slack, and by induction the greedy sequence of evictions is optimal throughout.
This is a different proof flavor from Job Sequencing's "schedule as late as possible" argument and from EDF's staying-ahead argument (see Part 16, Section 8) — it reasons about which single element to discard rather than about ordering the elements that remain.
Complexity
Sorting is $O(n \log n)$. Each of the $n$ jobs causes at most one heap push and at most one heap pop, each $O(\log n)$, so the scan is $O(n \log n)$ as well. Total time: $O(n \log n)$; space: $O(n)$ for the heap.
flowchart TD
A(["Sort jobs by deadline, ascending"]) --> B["Take next job in deadline order"]
B --> C["Push job onto max-heap (by processing time)\nrunning_time += p"]
C --> D{"running_time > this job's deadline?"}
D -->|"No"| E["Job stays scheduled (on time so far)"]
D -->|"Yes"| F["Pop job with LARGEST p from the heap\nMark it late; running_time -= its p"]
E --> G{"More jobs left?"}
F --> G
G -->|"Yes"| B
G -->|"No"| H(["Heap contents = on-time jobs\nPopped jobs = minimum possible late jobs"])
The heap makes the eviction step efficient: it always holds exactly the processing times of the currently-scheduled jobs, so "find and remove the largest" is one $O(\log n)$ pop instead of an $O(n)$ scan.
5. Smith's Rule (Weighted Shortest Processing Time)
Given $n$ jobs with processing times $p_i$ and weights $w_i$ (no deadlines at all), order them to minimize the total weighted completion time $\sum_i w_i C_i$, where $C_i$ is the time at which job $i$ finishes. A heavier weight represents a job whose customer cares more about a fast finish.
Proof Sketch: an Adjacent-Swap Exchange Argument
Consider two jobs $i$ and $j$ scheduled consecutively, with $i$ immediately before $j$, and let $t$ be the time everything before them finishes (fixed regardless of their internal order, since the pair still occupies exactly $p_i+p_j$ time either way). The weighted contribution of just this pair is:
$$\text{$i$ before $j$}: \quad w_i(t+p_i) + w_j(t+p_i+p_j)$$
$$\text{$j$ before $i$}: \quad w_j(t+p_j) + w_i(t+p_j+p_i)$$
Subtracting the two, every term involving $t$ and $p_i+p_j$ together cancels, leaving:
$$(\text{$i$ before $j$}) - (\text{$j$ before $i$}) = w_j p_i - w_i p_j$$
Running $i$ before $j$ is at least as good exactly when $w_j p_i \le w_i p_j$, i.e. when $p_i/w_i \le p_j/w_j$. So any adjacent pair that violates increasing-ratio order can be swapped without increasing the total weighted completion time, and swapping strictly decreases it whenever the ratios differ. Repeating this bubbles any schedule into Smith's Rule order without ever making things worse, so the fully-sorted order is optimal. This "adjacent swap" argument is a third distinct proof style in this lesson — different from Job Sequencing's exchange-with-optimal argument and from EDF's staying-ahead argument.
Complexity
A single sort by ratio: $O(n \log n)$ time, $O(n)$ space.
6. Earliest Deadline First (EDF)
EDF is a policy rather than a one-shot sort: at every decision point, run whichever available job has the nearest deadline. On a single machine with no preemption and all jobs available at time 0, always running in nearest-deadline order is equivalent to sorting once by deadline, which is exactly the order Moore-Hodgson and the worked example above scan in.
EDF answers two related questions:
- Feasibility: can every job meet its deadline at all? Simulate the deadline order once; if any job's cumulative completion time exceeds its own deadline, no schedule can meet every deadline (EDF is the most forgiving order, so if EDF fails, everything fails).
- Minimizing maximum lateness $L_{\max} = \max_i (C_i - d_i)$: when not every job can meet its deadline, EDF order still minimizes the worst single overrun.
The correctness argument, briefly: if two adjacent jobs run out of deadline order, swapping them to put the nearer deadline first cannot increase either job's lateness and cannot increase the schedule's maximum lateness — the later job in the swapped pair finishes exactly where the earlier one used to, and the lateness of every other job is unaffected. Repeating this bubbles any schedule into EDF order without ever increasing $L_{\max}$, so EDF order is optimal. That is a "staying ahead" style claim; the full inductive proof, with the loop invariant made precise, is worked out in Part 16, Section 8: Staying-Ahead Arguments, using EDF-minimizing-maximum-lateness as its worked example. Running the feasibility check on the five jobs from the worked example above reports infeasible right at job C (cumulative time 9 exceeds its deadline of 4) — exactly the point where Moore-Hodgson had to drop a job.
Feasibility-Check Implementation
7. Shortest Processing Time (SPT)
SPT always runs the shortest remaining job next. It is exactly Smith's Rule (Section 5) with every weight set to $w_i = 1$: the ratio $p_i/w_i$ collapses to $p_i$, so sorting by increasing ratio becomes sorting by increasing processing time. SPT minimizes the total (unweighted) completion time $\sum_i C_i$, which is equivalent to minimizing the average completion time and average waiting time across jobs — a common goal when every job matters equally and there are no deadlines.
SPT in Practice
Because SPT is Smith's Rule with unit weights, the Smith's Rule code above already implements it — call it with every weight equal to 1. A short illustrative version, sorting directly by processing time:
def spt_order(jobs):
"""
SPT: minimize total (unweighted) completion time.
jobs: list of (job_id, processing_time). Time: O(n log n), Space: O(n).
"""
ordered = sorted(jobs, key=lambda j: j[1]) # shortest processing time first
current_time = 0
total_completion = 0
for job_id, p in ordered:
current_time += p
total_completion += current_time
return [job_id for job_id, _ in ordered], total_completion
order, total = spt_order([("J1", 2), ("J2", 3), ("J3", 4)])
print("Order:", order) # Order: ['J1', 'J2', 'J3']
print("Total completion time:", total) # Total completion time: 2 + 5 + 9 = 16
8. Complexity Comparison
| Algorithm | Objective | Ordering Rule | Time | Space |
|---|---|---|---|---|
| Moore-Hodgson | Minimize number of late jobs | Sort by deadline; evict largest-$p$ scheduled job on overflow (max-heap) | $O(n \log n)$ | $O(n)$ |
| Smith's Rule | Minimize $\sum_i w_i C_i$ (total weighted completion time) | Sort by increasing $p_i / w_i$ | $O(n \log n)$ | $O(n)$ |
| EDF | Feasibility check; minimize maximum lateness $L_{\max}$ | Sort by deadline, ascending | $O(n \log n)$ | $O(n)$ |
| SPT | Minimize $\sum_i C_i$ (total/average completion time) | Sort by increasing processing time | $O(n \log n)$ | $O(n)$ |
Every one of these algorithms is dominated by its sort, so all four share the same $O(n \log n)$ time and $O(n)$ space bound. What differs is the comparator — and, for Moore-Hodgson, an extra data structure (the max-heap) needed to make the eviction step as cheap as the sort that surrounds it.
On the same three jobs, EDF order (P2, P3, P1) leaves only P1 late, and only by 1 unit — the minimum possible maximum lateness. SPT order (P3, P1, P2) finishes P2 five units after its deadline, but its total completion time (2+5+10=17) beats EDF's (5+7+10=22) — the minimum possible total completion time. Neither ordering is "better" in general; each is optimal for its own objective.
9. Applications and Alternatives
Where these orderings show up in real systems
- Operating system process scheduling: shortest-job-next schedulers approximate SPT to minimize average turnaround time; real-time operating systems use EDF (and rate-monotonic scheduling as a fixed-priority alternative) to guarantee deadline-bound tasks are met.
- Manufacturing and job-shop scheduling: a single bottleneck machine in a production line is a direct single-machine scheduling instance — Moore-Hodgson-style late-job minimization and Smith's Rule-style weighted-lateness minimization both appear in shop-floor sequencing software.
- Real-time and embedded systems: EDF is the classical dynamic-priority scheduling policy for hard deadline systems, alongside admission-control feasibility checks that use exactly the simulation in Section 6 before accepting a new periodic task.
These four rules only cover single-machine, non-preemptive, deadline-independent-of-order problems. Multiple machines, preemption, precedence constraints between jobs, and setup times between different job types each require different (and often NP-hard) formulations — the exercises below touch on precedence constraints as a preview of that harder territory.
10. Exercises and Mastery
Easy
- Given jobs (processing times only) $\{6, 2, 5, 1\}$, give the SPT order and compute the total completion time.
- For the same four jobs, compute the average (mean) completion time and explain why SPT minimizes it.
Medium
- Trace Moore-Hodgson on: P (p=3, d=3), Q (p=2, d=5), R (p=5, d=6), S (p=1, d=7), T (p=4, d=8). List the on-time set, the late set, and the running-time value at each step.
- Prove (or disprove with a counterexample) that the late set Moore-Hodgson produces is unique — is there ever more than one minimum-size late set for the same input?
Hard
- Suppose jobs carry weights and processing times as in Smith's Rule, but a precedence constraint requires job B to run only after job A completes (a chain of two jobs). Sorting each job independently by $p_i/w_i$ can now produce an infeasible order. Describe, in words, how you would adapt the ratio idea — consider treating the constrained chain as a single combined "super-job" with a combined ratio, and decide what that combined ratio should be. Code is optional; a correct written argument for why your combined-ratio approach preserves optimality is the goal.
Review rhythm: tomorrow, reconstruct all four ordering rules and which objective each solves, from memory. Next week, re-derive Smith's Rule's adjacent-swap inequality without looking it up, and re-implement Moore-Hodgson's eviction step with a heap. Several weeks later, work the precedence-constrained Hard exercise again and check whether your combined-ratio idea still holds up. Finally, teach someone who already knows Job Sequencing why deadlines-with-arbitrary-processing-times needs a completely different algorithm.
11. Summary Cheat Sheet
- Moore-Hodgson: minimize late jobs — sort by deadline, evict the largest-processing-time scheduled job whenever the running time overflows a deadline (max-heap).
- Smith's Rule (WSPT): minimize total weighted completion time — sort by increasing $p_i/w_i$ (adjacent-swap exchange argument).
- EDF: feasibility check and minimizing maximum lateness — always run the nearest deadline next (staying-ahead argument, proved in Part 16).
- SPT: minimize total/average completion time — Smith's Rule with every weight equal to 1.
- All four share $O(n \log n)$ time (one sort) and $O(n)$ space; the objective, not the machinery, is what changes.
- Job Sequencing (deadlines + profits, unit processing time, jobs can be skipped) is a related but distinct problem, covered in Part 16, not repeated here.