Java
random shuffling
algorithms
programming
probabilities

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.

Practice algorithms

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:

  1. Start from the end of the array.
  2. Pick a random index from the unshuffled prefix.
  3. Swap the current element with that random element.
  4. Continue until the array is exhausted.

Java implementation:

java
1import java.util.Arrays;
2import java.util.Random;
3
4public class ShuffleDemo {
5    public static void shuffle(int[] arr, Random random) {
6        for (int i = arr.length - 1; i > 0; i--) {
7            int j = random.nextInt(i + 1);
8            int temp = arr[i];
9            arr[i] = arr[j];
10            arr[j] = temp;
11        }
12    }
13
14    public static void main(String[] args) {
15        int[] arr = {1, 2, 3, 4, 5};
16        shuffle(arr, new Random());
17        System.out.println(Arrays.toString(arr));
18    }
19}

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.

java
1for (int i = 0; i < arr.length; i++) {
2    int j = random.nextInt(arr.length);
3    swap(arr, i, j);
4}

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 n elements with probability 1 / n.
  • Next position gets one of the remaining n - 1 elements with probability 1 / (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:

java
1import java.util.ArrayList;
2import java.util.Arrays;
3import java.util.Collections;
4import java.util.List;
5
6public class ShuffleListDemo {
7    public static void main(String[] args) {
8        List<Integer> values = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
9        Collections.shuffle(values);
10        System.out.println(values);
11    }
12}

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:

java
Collections.shuffle(values, new Random(1234));

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.shuffle is the right default in Java for list shuffling.'
  • Shuffle correctness and random generator quality are related but separate concerns.

Related reading
Course
Intermediate
27 lessons
15 hours
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 course
Track 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.

Practice algorithms

All Rights Reserved.