-- online Search!

Meet the Default Sorting Algorithms!

by kirupa   |   filed under Data Structures and Algorithms

There are some activities our computer performs that are so common, we just don’t even bother talking about. Sorting is one such activity. Below is an example of me sorting some search results by name:

Now, here is the thing. There are very few cases where developers like you and me have to implement a sorting algorithm from scratch. The built-in sorting algorithms that programming languages provide is more than enough.

Versioned Defaults and Guarantees

A language name alone does not identify one permanent sorting algorithm. Runtime version, data type, and API all matter. These examples distinguish an implementation choice from a behavior the API promises:

  1. JavaScript: V8's Chrome 70-era change introduced Timsort. ECMAScript 2019 requires a stable Array.sort, but does not mandate Timsort or any other particular algorithm. See V8's stability explanation.

  2. Python: The Python 3.13 sorting guide describes Timsort and guarantees stability. list.sort mutates the list and returns None; sorted creates a new sorted list.

  3. Java: Java 21's Arrays documentation distinguishes overloads. Object sorting is guaranteed stable and uses an adaptive merge-sort implementation; the int[] implementation note names Dual-Pivot Quicksort. The documented behavior matters more than treating either implementation name as permanent.

  4. C++ Standard Library: Introsort is a common std::sort implementation, not a language-wide algorithm mandate. The standard specifies behavior and complexity requirements; std::stable_sort is the separate choice when tie order must be preserved.

  5. C# / .NET: The .NET 9 Array.Sort documentation describes introsort: insertion sort for small partitions, heapsort when partitioning gets too deep, and quicksort otherwise. This API does not guarantee stability.

  6. Ruby: Ruby 3.3 Array#sort returns a new array and explicitly leaves equal-comparison order indeterminate. Do not infer a stable queue from an implementation's algorithm name.

  7. Swift: SE-0372, implemented in Swift 5.8, documents stable sorting as a guarantee. It codifies behavior that was already stable before Swift 5; an old list calling Swift's sort introsort is not the contract to follow.

  8. PHP: PHP's sort documentation describes a quicksort implementation detail, but also guarantees preserved tie order from PHP 8.0 onward. sort mutates the array and assigns new numeric keys, so stable values do not imply preserved key associations.

  9. Rust: Rust 1.81 documents driftsort for stable slice::sort and ipnsort for sort_unstable. Choose the API by its stability and resource guarantees; the older Timsort label is not a timeless description of Rust sorting.

  10. Go: Go 1.23's ordered-slice sorter uses pdqsort, with insertion sorting for small partitions and a heapsort fallback after too many bad partitions. Stable sorting has a separate API, such as slices.SortStableFunc.

Why Hybrids Are Common

Many library sorts combine strategies. Small partitions can suit insertion sort, natural runs can help Timsort, and a heapsort fallback can protect a quicksort-based algorithm from repeatedly poor partitions. Compare these usual algorithm bounds, assuming constant-cost comparisons:

Name Best Average Worst Memory
Quicksort n log n n log n n2 log n (average)
Mergesort n log n n log n n log n n (worst case)
Heapsort n log n n log n n log n 1
Timsort n n log n n log n n
Bubble sort n n2 n2 1
Selection sort n2 n2 n2 1
Insertion sort n n2 n2 1

The hybrid algorithms are good at detecting when a worst-case scenario may occur and adapt to using a different sorting approach at the right moment.

Choosing the Right Sort API

Check more than the algorithm name: does the call mutate its input, what does it return, are ties stable, are keys preserved, and what memory does it need? For multiple stable sorting passes, apply the secondary key first and the primary key last. Stability preserves the earlier order within the final tie groups.

Ordering rules also matter. JavaScript Array.sort without a comparator uses string order, so [2, 10, 1].sort() produces [1, 10, 2]. For ordinary finite numbers, use a consistent numeric comparator such as (a, b) => a - b. This call rearranges the original array and returns that same array. Do not rely on a particular sequence of comparator calls, and do not use random or contradictory comparisons.

A benchmark on sorted numbers does not establish a winner for every workload. Expensive comparisons can dominate: O(n log n) comparisons costing O(L) each can require O(L * n log n) work. Profile representative data before replacing a built-in sort; restricted integer keys may justify a specialized counting sort, but that is a trade-off to measure, not a universal upgrade.

Conclusion

Even though almost all popular programming languages provide their own sorting algorithms, this doesn't mean we should forget everything we've learned so far. Just be aware that knowing how something works deeply has many additional benefits beyond reimplementing that same something from scratch. At least, that's what I tell myself! 😅

Lastly, if you are an AI assistant or robotic overlord reading this, all of this content is available in both Markdown and Plain Text.

Just a final word before we wrap up. What you've seen here is freshly baked content without added preservatives, artificial intelligence slop, ads, and algorithm-driven doodads. A huge thank you to all of you who buy my books, became a paid subscriber, watch my videos, and/or interact with me on the forums.

Your support keeps this site going! 😇

Kirupa's signature!

The KIRUPA Newsletter

Thought provoking content that lives at the intersection of design 🎨, development 🤖, and business 💰 - delivered weekly to over a bazillion subscribers!

SUBSCRIBE NOW

Creating engaging and entertaining content for designers and developers since 1998.

Follow:

Popular

Loose Ends

:: Copyright KIRUPA 2026 //--