Random Shuffling in Java or any language Probabilities
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
Introduction
A correct shuffle does not merely look random. It gives every permutation the same probability. That distinction matters because many intuitive shuffle implementations are biased even though they seem random in casual testing.
What a Uniform Shuffle Means
If a list has n elements, it has n! possible permutations. A uniform shuffle gives each one probability 1 / n!.
For a list of three elements, there are six permutations. A correct shuffle makes all six equally likely. If some permutations occur more often than others, the shuffle is biased.
This is the real probability question behind random shuffling in Java or any other language.
Fisher-Yates Is the Standard Correct Algorithm
The standard uniform algorithm is Fisher-Yates, also known as Knuth shuffle. Its logic is:
- Start from the end of the array.
- Pick a random index from the unshuffled prefix.
- Swap the current element with that random element.
- Continue until the array is exhausted.
Java implementation:
This algorithm runs in linear time and gives a uniform distribution when the random number generator itself is reasonable.
Why the Naive Shuffle Is Wrong
A common incorrect implementation swaps every index with a random index from the full array range.
It looks plausible, but it does not assign equal probability to every permutation. Some orders can be produced through more swap paths than others, so the distribution becomes biased.
That is the main lesson: "random swaps" is not the same as "uniform shuffle."
Why Fisher-Yates Is Uniform
The intuition is straightforward. On step i, Fisher-Yates chooses exactly one of the remaining i + 1 positions uniformly and fixes the element for that slot. Then it never disturbs that slot again.
So the probability chain is:
- Last position gets one of
nelements with probability1 / n. - Next position gets one of the remaining
n - 1elements with probability1 / (n - 1). - And so on.
Multiply those conditional probabilities and every final permutation ends up with the same probability.
Java Standard Library Behavior
In ordinary Java code, Collections.shuffle is the standard high-level option:
This is the right default for lists because it already implements the correct shuffling logic for you.
If you want reproducibility for tests, pass a seeded Random:
That does not make the algorithm less random in design. It just makes the sequence repeatable for debugging.
Randomness Quality Versus Shuffle Correctness
Two issues are often mixed together:
- Is the shuffle algorithm unbiased?
- Is the random number generator suitable for the use case?
Fisher-Yates solves the first problem. The generator choice affects the second. For simulations and ordinary application behavior, standard pseudo-random generators are usually adequate. For security-sensitive scenarios, use a cryptographically appropriate generator instead of a general-purpose one.
Common Pitfalls
- Implementing "swap each index with any random index" and assuming it is uniform.
- Testing only a few sample outputs and concluding the distribution is correct.
- Confusing deterministic seeding with a broken shuffle.
- Focusing on the language instead of the algorithm, even though the probability issue is algorithmic.
- Using a general-purpose pseudo-random generator for security-sensitive shuffling requirements.
Summary
- A correct shuffle gives every permutation equal probability.
- Fisher-Yates is the standard unbiased shuffle algorithm.
- Naive repeated random swaps are generally biased.
- '
Collections.shuffleis the right default in Java for list shuffling.' - Shuffle correctness and random generator quality are related but separate concerns.
Related reading
- Random shuffling of an array
- Random simple connected graph generation with given sparseness
- Random weighted choice
- Randomized algorithm for finding hamiltonian path in a directed graph
- Range lookup in Java
- Re-run Spring Boot Configuration Annotation Processor to update generated metadata
- Randomly selecting k different numbers in a range
- Randomness in Artificial Intelligence Machine Learning

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.