V

Algorithm Visualizer

ZHEN
Share on WeiboShare on XGitHub repositoryAuthor website
Learning ToolsAlgorithm Complexity ReferenceAlgorithm Learning Paths
Data StructuresArrayLinked ListStackQueue and DequeBinary Search TreeBinary HeapHash TableGraphTrieDisjoint Set UnionLRU CacheSkip ListSegment TreeB+ TreeBloom FilterFenwick Tree
SortingBubble SortCocktail Shaker SortBitonic SortSelection SortInsertion SortBinary Insertion SortShell SortMerge SortTop-Down Merge SortQuick SortThree-Way Quick SortDual-Pivot Quick SortHeap SortCounting SortRadix SortBucket Sort
Graph AlgorithmsDijkstra's Shortest PathKruskal's Minimum Spanning TreePrim's Minimum Spanning TreeBellman-Ford Shortest PathsTopological SortFloyd-WarshallStrongly Connected Components2-SATMaximum FlowBipartite MatchingLowest Common AncestorEulerian Path
Dynamic ProgrammingEdit Distance0/1 KnapsackUnbounded KnapsackLongest Common SubsequenceLongest Increasing SubsequenceCoin ChangeStone MergingTraveling Salesperson DPTree Dynamic ProgrammingDigit DPRerooting DP
Backtracking and SearchN-QueensSubsetsPermutationsCombination SumMaze Solving with DFSNumber of IslandsWord SearchSudoku SolverA* Search
StringsKMP String MatchingRabin-Karp String MatchingBoyer-Moore String MatchingManacher's Longest Palindromic SubstringSuffix ArrayLCP ArrayAho-Corasick AutomatonZ Function
Math and Number TheorySieve of EratosthenesLinear SieveEuclidean AlgorithmBinary ExponentiationExtended Euclidean AlgorithmChinese Remainder TheoremEuler's Totient FunctionMiller-Rabin Primality TestFast Fourier TransformPollard's Rho Factorization
Computational GeometryConvex HullRotating CalipersClosest Pair of PointsLine Segment IntersectionBentley-Ottmann Sweep Line
SearchingBinary SearchLower and Upper BoundSearch in a Rotated Sorted ArrayBinary Search on the AnswerTernary Search

Dual-Pivot Quick Sort

Choose two pivots and partition one interval into three regions during a single scan.

Core idea

Order two endpoint pivots p and q, then divide the scan into values below p, between p and q, and above q. Placing both pivots finishes three subproblems at once.

Read the visualization

Two pivot markers remain visible while lt, i, and gt move the unknown region inward. Each comparison selects one of the three partition branches.

3
5
9
1
6
2
4
7
Interval stack: each frame is a pending subarray a[lo..hi]
Stack empty: every position is final

Take the next unsorted interval from the work stack.

1function dualPivotQuickSort(a: number[]): number[] {
2 const stack: [number, number][] = [[0, a.length - 1]];
3 while (stack.length > 0) {
4 const [lo, hi] = stack.pop()!;
5 if (a[lo] > a[hi]) [a[lo], a[hi]] = [a[hi], a[lo]];
6 const p = a[lo], q = a[hi];
7 let lt = lo + 1, i = lo + 1, gt = hi - 1;
8 while (i <= gt) {
9 if (a[i] < p) {
10 [a[lt], a[i]] = [a[i], a[lt]];
11 lt++; i++;
12 } else if (a[i] > q) {
13 [a[i], a[gt]] = [a[gt], a[i]];
14 gt--;
15 } else {
16 i++;
17 }
18 }
19 lt--; gt++;
20 [a[lo], a[lt]] = [a[lt], a[lo]];
21 [a[hi], a[gt]] = [a[gt], a[hi]];
22 if (hi > gt + 1) stack.push([gt + 1, hi]);
23 if (gt - 1 > lt + 1) stack.push([lt + 1, gt - 1]);
24 if (lt - 1 > lo) stack.push([lo, lt - 1]);
25 }
26 return a;
27}
n8
stack deep0
lo0
hi7
p-
q-
lt-
i-
gt-
1 / 27

Complexity and tradeoffs

Time: Average O(n log n); worst O(n^2). Space: Average O(log n). Good partitions reduce recursion depth and can improve cache behavior, but the worst case remains quadratic.

Invariant: The outer regions are already classified relative to p and q, and only the interval between i and gt remains unknown.

Where it fits

Dual-pivot partitioning can reduce comparisons and improve cache behavior in tuned primitive-array sorts. Pivot selection remains essential to avoid unbalanced recursion.