How does a genetic algorithm work?

Updated Feb 20, 2026

Short answer

A genetic algorithm evolves a population of candidate solutions towards better ones by mimicking natural selection. Each generation scores every candidate with a fitness function, selects the fitter ones to reproduce, combines pairs via crossover, applies random mutation, and repeats. It is a stochastic search for problems where the space is too large to enumerate and no gradient is available.

Deep explanation

Python
def genetic_algorithm(fitness, population_size, generations):
population = [random_individual() for _ in range(population_size)]
for _ in range(generations):
scored = sorted(population, key=fitness, reverse=True)
elite = scored[:2] # ELITISM: keep the best unchanged
children = []
while len(children) < population_size - len(elite):
p1, p2 = tournament_select(scored, fitness), tournament_select(scored, fitness)
child = crossover(p1, p2)
if random.random() < 0.02: # low mutation rate
child = mutate(child)
children.append(child)
population = elite + children
return max(population, key=fitness)

The five components, and what each contributes:

  • Representation — how a solution is encoded. This is the most consequential design decision; a poor encoding makes crossover produce nonsense.
  • Fitness function — scores a candidate. Called constantly, so its cost dominates runtime.
  • Selection — biases reproduction towards fitter individuals. Tournament selection (pick k at random, keep the best) is usual because it is cheap and its selection pressure is tunable via k.
  • Crossover — combines two parents, the exploitation mechanism, recombining building blocks that already work.
  • Mutation — random perturbation, the exploration mechanism, reintroducing lost diversity.

The central tension is exploration against exploitation. Too much selection pressure and the population converges prematurely on a local optimum, all individuals nearly identical and crossover producing nothing new. Too much mutation and it degenerates into random search. Mutation rates are typically 0.1–5%.

Elitism matters more than it looks. Without carrying the best individuals forward unchanged, a good solution can be lost to unlucky crossover, and fitness can go down between generations.

When a GA is the right tool: the search space is huge and discrete, the fitness landscape is rugged with many local optima, there is no gradient to follow, and a good-enough answer is acceptable. Scheduling, routing, circuit layout, hyperparameter search, and neural architecture search all fit.

When it is not: if the problem is convex or differentiable, gradient descent is far faster. If an exact algorithm exists — shortest path, linear programming — use it. GAs guarantee nothing about optimality and require substantial tuning.

Real-world example

Scheduling exams to minimise conflicts:

Python
# representation: a list where index = exam, value = time slot
individual = [2, 0, 1, 2, 3, 0] # exam 0 in slot 2, exam 1 in slot 0, ...
def fitness(schedule):
conflicts = sum(1 for a, b in student_pairs()
if schedule[a] == schedule[b]) # same student, same slot
slots_used = len(set(schedule))
return -(conflicts * 100 + slots_used) # conflicts dominate

Crossover takes slot assignments from both parents, mutation reassigns one exam to a random slot. With 200 exams and 20 slots the space is 20²⁰⁰ — no enumeration is possible, and there is no gradient to descend, but a GA reliably finds a workable timetable within a few thousand generations.

The weighting in the fitness function is doing real work: conflicts cost 100× a slot, so the search prioritises validity over compactness.

Common mistakes

  • - Choosing a representation where crossover produces invalid individuals, then repairing them constantly — which usually means the encoding is wrong.
  • - Setting the mutation rate too high, degrading the search into random sampling and destroying the building blocks crossover assembles.
  • - Omitting elitism, so the best solution found can be lost and fitness regresses between generations.
  • - Applying excessive selection pressure, causing premature convergence on a local optimum with a population of near-identical clones.
  • - Using a GA on a convex or differentiable problem where gradient descent would be orders of magnitude faster.
  • - Writing an expensive fitness function without profiling
  • it is evaluated population_size × generations times and dominates everything else.

Follow-up questions

  • What is premature convergence and how do you counter it?
  • Why is elitism important?
  • How do you choose a selection method?
  • When is simulated annealing preferable to a genetic algorithm?

More Genetic Algorithms interview questions

View all →