Chapter 8: Arrays and Dynamic Arrays
8.07Beginner / Intermediate5 topics16 min5 interactive animations

Partitioning problems

Partitioning rearranges an array so that elements satisfying a condition come first. This lesson covers the Dutch national flag, partitioning by a pivot, alternating signs, stable versus unstable partitions and the three-way partition used by quicksort.

Learning goals

  • Partition an array in place in one pass
  • Maintain invariants with lo, mid and hi pointers
  • Choose between stable (extra space) and unstable (in place) partitions

Prerequisites

One-dimensional patternsTwo pointers
8.07.1

Dutch national flag

Sort an array containing only 0, 1 and 2 in one pass and O(1) space, as if sorting the three stripes of the Dutch flag. Maintain three zones with pointers: [0, lo) holds 0s, [lo, mid) holds 1s, (hi, n) holds 2s, and [mid, hi] is unexamined. Dijkstra's solution handles each element once.

The first preset is exactly this problem, with pivot value 1.

Java
1static void sortColors(int[] a) {
2 int lo = 0, mid = 0, hi = a.length - 1;
3 while (mid <= hi) {
4 if (a[mid] == 0) swap(a, lo++, mid++);
5 else if (a[mid] == 2) swap(a, mid, hi--); // do not advance mid: the swapped-in value is unexamined
6 else mid++;
7 }
8}

Three-way partition (Dutch national flag)

Interactive · edit the input

Your input

Try

int[] arr · length 6

2
0
2
1
1
0
0123456
< pivot= pivot> pivotExaminingUnclassified
Setup

Three zones grow from the edges toward the unclassified middle: less than 1, equal to 1, greater than 1.

Step 1 / 14
Java
1static void partition3(int[] a, int pivot) {
2 int lo = 0, mid = 0, hi = a.length - 1; // [0,lo) < pivot, [lo,mid) == pivot, (hi,n) > pivot
3 while (mid <= hi) {
4 if (a[mid] < pivot) swap(a, lo++, mid++);
5 else if (a[mid] > pivot) swap(a, mid, hi--);
6 else mid++;
7 }
8}

Live state

0 swaps

lo

0

mid

0

hi

5

pivot

1

No condition evaluated on this step
Execution trace (dry run table)Show 14 steps
StepLineStateWhat happens
1L2lo=0 mid=0 hi=5 pivot=1Three zones grow from the edges toward the unclassified middle: less than 1, equal to 1, greater than 1.
2L4lo=0 mid=0 hi=5 a[mid]=22 > 1: swap it to the right end and shrink hi. Do not advance mid: the swapped-in value is unexamined.
3L5lo=0 mid=0 hi=4Zones now: less [0,0), equal [0,0), greater (4,5].
4L4lo=0 mid=0 hi=4 a[mid]=00 < 1: swap it into the "less" zone and advance lo and mid.
5L4lo=1 mid=1 hi=4Zones now: less [0,1), equal [1,1), greater (4,5].
6L4lo=1 mid=1 hi=4 a[mid]=00 < 1: swap it into the "less" zone and advance lo and mid.
7L4lo=2 mid=2 hi=4Zones now: less [0,2), equal [2,2), greater (4,5].
8L4lo=2 mid=2 hi=4 a[mid]=22 > 1: swap it to the right end and shrink hi. Do not advance mid: the swapped-in value is unexamined.
9L5lo=2 mid=2 hi=3Zones now: less [0,2), equal [2,2), greater (3,5].
10L4lo=2 mid=2 hi=3 a[mid]=11 equals the pivot: it is already in the middle zone, advance mid.
11L6lo=2 mid=3 hi=3Zones now: less [0,2), equal [2,3), greater (3,5].
12L4lo=2 mid=3 hi=3 a[mid]=11 equals the pivot: it is already in the middle zone, advance mid.
13L6lo=2 mid=4 hi=3Zones now: less [0,2), equal [2,4), greater (3,5].
14L8lo=2 mid=4 hi=3 swaps=2Partitioned in one pass with 2 swaps: 2 less, 2 equal, 2 greater. O(n) time, O(1) space. This is the partition step of 3-way quicksort.
8.07.2

Partition by pivot

Partitioning by a pivot value moves every element smaller than the pivot to the left and the rest to the right. The Lomuto scheme keeps a store index of the next slot for a small value and swaps each small element into it. It returns how many values are smaller. One pass, O(n) time, O(1) space, not stable.

This is the heart of quicksort and quickselect.

Java
1static int partition(int[] a, int pivot) { // returns the count of values < pivot
2 int store = 0;
3 for (int i = 0; i < a.length; i++) {
4 if (a[i] < pivot) { swap(a, store, i); store++; }
5 }
6 return store;
7}

Partition by a pivot value (Lomuto style)

Interactive · edit the input

Your input

Try

int[] arr · length 7

7
2
9
4
1
8
3
01234567
< pivotScanningNot yet scanned or >= pivot
Setup

store marks where the next value smaller than 5 belongs; everything left of it is already smaller.

Step 1 / 13
Java
1static int partition(int[] a, int pivot) { // returns how many values are < pivot
2 int store = 0;
3 for (int i = 0; i < a.length; i++) {
4 if (a[i] < pivot) {
5 swap(a, store, i);
6 store++;
7 }
8 }
9 return store;
10}

Live state

0 swaps

store

0

pivot

5

No condition evaluated on this step
Execution trace (dry run table)Show 13 steps
StepLineStateWhat happens
1L2store=0 pivot=5store marks where the next value smaller than 5 belongs; everything left of it is already smaller.
2L4i=0 store=0 a[i]=77 >= 5: leave it on the right.
3L4i=1 store=0 a[i]=22 < 5: it belongs in the left part.
4L6i=1 store=1Swapped into position 0; store = 1.
5L4i=2 store=1 a[i]=99 >= 5: leave it on the right.
6L4i=3 store=1 a[i]=44 < 5: it belongs in the left part.
7L6i=3 store=2Swapped into position 1; store = 2.
8L4i=4 store=2 a[i]=11 < 5: it belongs in the left part.
9L6i=4 store=3Swapped into position 2; store = 3.
10L4i=5 store=3 a[i]=88 >= 5: leave it on the right.
11L4i=6 store=3 a[i]=33 < 5: it belongs in the left part.
12L6i=6 store=4Swapped into position 3; store = 4.
13L9return=4 swaps=4Return 4: the first 4 slots hold values < 5, the rest are >= 5. One pass, order inside each part is not preserved.
8.07.3

Alternate signs

Rearranging so that signs alternate (positives at even indexes, negatives at odd) while keeping the relative order within each sign is easy with an output array and two write indexes advancing by 2. It needs equal numbers of positives and negatives (and no zeros) for a perfect alternation.

The order-preserving in-place variant requires rotations and costs O(n²).

Java
1static int[] rearrange(int[] a) {
2 int[] out = new int[a.length];
3 int pos = 0, neg = 1;
4 for (int x : a) {
5 if (x > 0) { out[pos] = x; pos += 2; } else { out[neg] = x; neg += 2; }
6 }
7 return out;
8}

Rearrange to alternate positive and negative

Interactive · edit the input

Your input

Try

int[] arr · length 6

3
1
-2
-5
2
-4
012345
Value being placedPlaced

out[]

·0
·1
·2
·3
·4
·5
Setup

Positives fill the even indexes 0, 2, 4 ... and negatives the odd indexes 1, 3, 5 ... Each group keeps its original order.

Step 1 / 8
Java
1static int[] rearrange(int[] a) { // equal numbers of positives and negatives
2 int[] out = new int[a.length];
3 int pos = 0, neg = 1; // positives take even slots, negatives odd slots
4 for (int x : a) {
5 if (x > 0) { out[pos] = x; pos += 2; }
6 else { out[neg] = x; neg += 2; }
7 }
8 return out;
9}

Live state

pos

0

neg

1

No condition evaluated on this step
Execution trace (dry run table)Show 8 steps
StepLineStateWhat happens
1L3pos=0 neg=1Positives fill the even indexes 0, 2, 4 ... and negatives the odd indexes 1, 3, 5 ... Each group keeps its original order.
2L5i=0 x=3 pos=2 neg=13 is positive: out[0] = 3, next positive slot 2.
3L5i=1 x=1 pos=4 neg=11 is positive: out[2] = 1, next positive slot 4.
4L6i=2 x=-2 pos=4 neg=3-2 is negative: out[1] = -2, next negative slot 3.
5L6i=3 x=-5 pos=4 neg=5-5 is negative: out[3] = -5, next negative slot 5.
6L5i=4 x=2 pos=6 neg=52 is positive: out[4] = 2, next positive slot 6.
7L6i=5 x=-4 pos=6 neg=7-4 is negative: out[5] = -4, next negative slot 7.
8L8return=[3, -2, 1, -5, 2, -4]Result [3, -2, 1, -5, 2, -4]: one pass, O(n) time and O(n) extra space. The in-place version is much harder because order within each sign is lost or costs shifts.
8.07.4

Stable vs unstable partition

A stable partition keeps the original relative order inside each group; an unstable one may reorder equal-group elements. The stable version needs O(n) extra space (or O(n log n) time in place). The two-pointer version uses O(1) space but its long-distance swaps can reorder values.

Run both methods on the same duplicated input and compare the a/b tags.

MethodTimeExtra spaceStable?
Copy evens then oddsO(n)O(n)yes
Two pointers swapO(n)O(1)no
Stable in place (rotations)O(n log n)O(log n)yes

Stable vs unstable partition (evens first)

Interactive · edit the input

Your input

Try

int[] arr · length 7

3a
2a
3b
4a
2b
7
4b
0123456
Being comparedSwappedEven, placedaEqual keys in original order

out[]

empty
Setup

Pass 1 copies the even values in order, pass 2 copies the odd values in order.

Step 1 / 16
Java
1// stable: evens first, relative order kept, O(n) extra space
2static int[] stablePartition(int[] a) {
3 int[] out = new int[a.length]; int w = 0;
4 for (int x : a) if (x % 2 == 0) out[w++] = x;
5 for (int x : a) if (x % 2 != 0) out[w++] = x;
6 return out;
7}
8// unstable: O(1) extra space, order not kept
9static void unstablePartition(int[] a) {
10 int l = 0, r = a.length - 1;
11 while (l < r) {
12 if (a[l] % 2 == 0) l++;
13 else if (a[r] % 2 != 0) r--;
14 else swap(a, l++, r--);
15 }
16}

Live state

0 swaps
No condition evaluated on this step
Execution trace (dry run table)Show 16 steps
StepLineStateWhat happens
1L3Pass 1 copies the even values in order, pass 2 copies the odd values in order.
2L4i=0 x=3 w=03 is odd: skip in this pass.
3L4i=1 x=2 w=12 is even: copy to out[0].
4L4i=2 x=3 w=13 is odd: skip in this pass.
5L4i=3 x=4 w=24 is even: copy to out[1].
6L4i=4 x=2 w=32 is even: copy to out[2].
7L4i=5 x=7 w=37 is odd: skip in this pass.
8L4i=6 x=4 w=44 is even: copy to out[3].
9L5i=0 x=3 w=53 is odd: copy to out[4].
10L5i=1 x=2 w=52 is even: skip in this pass.
11L5i=2 x=3 w=63 is odd: copy to out[5].
12L5i=3 x=4 w=64 is even: skip in this pass.
13L5i=4 x=2 w=62 is even: skip in this pass.
14L5i=5 x=7 w=77 is odd: copy to out[6].
15L5i=6 x=4 w=74 is even: skip in this pass.
16L6return=[2, 4, 2, 4, 3, 3, 7]Equal values keep their original a, b, c order: the partition is stable. Cost: an extra O(n) array.
8.07.5

Three-way partition

A three-way partition splits around a pivot value into less, equal and greater. Handling the equal elements in one block is what makes three-way quicksort fast on inputs with many duplicates. It generalises the Dutch flag to an arbitrary pivot.

Choose a pivot that is not in the array, or one that appears many times, and watch the three zones.

Java
1static void partition3(int[] a, int pivot) {
2 int lo = 0, mid = 0, hi = a.length - 1;
3 while (mid <= hi) {
4 if (a[mid] < pivot) swap(a, lo++, mid++);
5 else if (a[mid] > pivot) swap(a, mid, hi--);
6 else mid++;
7 }
8}

Three-way partition (Dutch national flag)

Interactive · edit the input

Your input

Try

int[] arr · length 6

2
0
2
1
1
0
0123456
< pivot= pivot> pivotExaminingUnclassified
Setup

Three zones grow from the edges toward the unclassified middle: less than 1, equal to 1, greater than 1.

Step 1 / 14
Java
1static void partition3(int[] a, int pivot) {
2 int lo = 0, mid = 0, hi = a.length - 1; // [0,lo) < pivot, [lo,mid) == pivot, (hi,n) > pivot
3 while (mid <= hi) {
4 if (a[mid] < pivot) swap(a, lo++, mid++);
5 else if (a[mid] > pivot) swap(a, mid, hi--);
6 else mid++;
7 }
8}

Live state

0 swaps

lo

0

mid

0

hi

5

pivot

1

No condition evaluated on this step
Execution trace (dry run table)Show 14 steps
StepLineStateWhat happens
1L2lo=0 mid=0 hi=5 pivot=1Three zones grow from the edges toward the unclassified middle: less than 1, equal to 1, greater than 1.
2L4lo=0 mid=0 hi=5 a[mid]=22 > 1: swap it to the right end and shrink hi. Do not advance mid: the swapped-in value is unexamined.
3L5lo=0 mid=0 hi=4Zones now: less [0,0), equal [0,0), greater (4,5].
4L4lo=0 mid=0 hi=4 a[mid]=00 < 1: swap it into the "less" zone and advance lo and mid.
5L4lo=1 mid=1 hi=4Zones now: less [0,1), equal [1,1), greater (4,5].
6L4lo=1 mid=1 hi=4 a[mid]=00 < 1: swap it into the "less" zone and advance lo and mid.
7L4lo=2 mid=2 hi=4Zones now: less [0,2), equal [2,2), greater (4,5].
8L4lo=2 mid=2 hi=4 a[mid]=22 > 1: swap it to the right end and shrink hi. Do not advance mid: the swapped-in value is unexamined.
9L5lo=2 mid=2 hi=3Zones now: less [0,2), equal [2,2), greater (3,5].
10L4lo=2 mid=2 hi=3 a[mid]=11 equals the pivot: it is already in the middle zone, advance mid.
11L6lo=2 mid=3 hi=3Zones now: less [0,2), equal [2,3), greater (3,5].
12L4lo=2 mid=3 hi=3 a[mid]=11 equals the pivot: it is already in the middle zone, advance mid.
13L6lo=2 mid=4 hi=3Zones now: less [0,2), equal [2,4), greater (3,5].
14L8lo=2 mid=4 hi=3 swaps=2Partitioned in one pass with 2 swaps: 2 less, 2 equal, 2 greater. O(n) time, O(1) space. This is the partition step of 3-way quicksort.

Practice ladder

Now try it yourself

Easy

  • Sort {2, 0, 1, 2, 1, 0} with the Dutch flag method
  • Partition {7, 2, 9, 4} around pivot 5

Medium

  • Explain why mid is not advanced after swapping with hi
  • Partition an array so evens come first, stably

Advanced

  • Implement three-way quicksort and show it is O(n) on an array with only 3 distinct values

Key takeaways

  • Partitioning is one pass with pointers that maintain zone invariants.
  • Three zones (less, equal, greater) handle duplicates efficiently.
  • Stable partitions cost extra space or time; unstable ones are in place.