Skip to content

Commit a1c4d85

Browse files
Sorting documentation fixups for 1.9 (#48440)
- Fix typos - Clarify that ! means mutation, not "in-place-ness". This should be backported because sort! is even less in place in 1.9 than it already was in 1.8. - Rewrite the section on default policy to reflect the new default policy - Move examples and extended description of previously default sorting algorithms out of sort.md and into their respective docstrings (still rendered in sort.md) Co-authored-by: Jeremie Knuesel <knuesel@gmail.com>
1 parent 7e8515c commit a1c4d85

File tree

2 files changed

+39
-57
lines changed

2 files changed

+39
-57
lines changed

base/sort.jl

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ Base.size(v::WithoutMissingVector) = size(v.data)
524524
send_to_end!(f::Function, v::AbstractVector; [lo, hi])
525525
526526
Send every element of `v` for which `f` returns `true` to the end of the vector and return
527-
the index of the last element which for which `f` returns `false`.
527+
the index of the last element for which `f` returns `false`.
528528
529529
`send_to_end!(f, v, lo, hi)` is equivalent to `send_to_end!(f, view(v, lo:hi))+lo-1`
530530
@@ -1242,7 +1242,7 @@ Otherwise, we dispatch to [`InsertionSort`](@ref) for inputs with `length <= 40`
12421242
perform a presorted check ([`CheckSorted`](@ref)).
12431243
12441244
We check for short inputs before performing the presorted check to avoid the overhead of the
1245-
check for small inputs. Because the alternate dispatch is to [`InseritonSort`](@ref) which
1245+
check for small inputs. Because the alternate dispatch is to [`InsertionSort`](@ref) which
12461246
has efficient `O(n)` runtime on presorted inputs, the check is not necessary for small
12471247
inputs.
12481248
@@ -1891,6 +1891,26 @@ Characteristics:
18911891
ignores case).
18921892
* *in-place* in memory.
18931893
* *divide-and-conquer*: sort strategy similar to [`MergeSort`](@ref).
1894+
1895+
Note that `PartialQuickSort(k)` does not necessarily sort the whole array. For example,
1896+
1897+
```jldoctest
1898+
julia> x = rand(100);
1899+
1900+
julia> k = 50:100;
1901+
1902+
julia> s1 = sort(x; alg=QuickSort);
1903+
1904+
julia> s2 = sort(x; alg=PartialQuickSort(k));
1905+
1906+
julia> map(issorted, (s1, s2))
1907+
(true, false)
1908+
1909+
julia> map(x->issorted(x[k]), (s1, s2))
1910+
(true, true)
1911+
1912+
julia> s1[k] == s2[k]
1913+
true
18941914
"""
18951915
struct PartialQuickSort{T <: Union{Integer,OrdinalRange}} <: Algorithm
18961916
k::T
@@ -1927,6 +1947,8 @@ Characteristics:
19271947
case).
19281948
* *not in-place* in memory.
19291949
* *divide-and-conquer* sort strategy.
1950+
* *good performance* for large collections but typically not quite as
1951+
fast as [`QuickSort`](@ref).
19301952
"""
19311953
const MergeSort = MergeSortAlg()
19321954

doc/src/base/sort.md

Lines changed: 15 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ julia> sort([2,3,1], rev=true)
2121
1
2222
```
2323

24-
To sort an array in-place, use the "bang" version of the sort function:
24+
`sort` constructs a sorted copy leaving its input unchanged. Use the "bang" version of
25+
the sort function to mutate an existing array:
2526

2627
```jldoctest
2728
julia> a = [2,3,1];
@@ -134,74 +135,33 @@ Base.Sort.partialsortperm!
134135

135136
## Sorting Algorithms
136137

137-
There are currently four sorting algorithms available in base Julia:
138+
There are currently four sorting algorithms publicly available in base Julia:
138139

139140
* [`InsertionSort`](@ref)
140141
* [`QuickSort`](@ref)
141142
* [`PartialQuickSort(k)`](@ref)
142143
* [`MergeSort`](@ref)
143144

144-
`InsertionSort` is an O(n²) stable sorting algorithm. It is efficient for very small `n`,
145-
and is used internally by `QuickSort`.
145+
By default, the `sort` family of functions uses stable sorting algorithms that are fast
146+
on most inputs. The exact algorithm choice is an implementation detail to allow for
147+
future performance improvements. Currently, a hybrid of `RadixSort`, `ScratchQuickSort`,
148+
`InsertionSort`, and `CountingSort` is used based on input type, size, and composition.
149+
Implementation details are subject to change but currently available in the extended help
150+
of `??Base.DEFAULT_STABLE` and the docstrings of internal sorting algorithms listed there.
146151

147-
`QuickSort` is a very fast sorting algorithm with an average-case time complexity of
148-
O(n log n). `QuickSort` is stable, i.e., elements considered equal will remain in the same
149-
order. Notice that O(n²) is worst-case complexity, but it gets vanishingly unlikely as the
150-
pivot selection is randomized.
151-
152-
`PartialQuickSort(k::OrdinalRange)` is similar to `QuickSort`, but the output array is only
153-
sorted in the range of `k`. For example:
154-
155-
```jldoctest
156-
julia> x = rand(1:500, 100);
157-
158-
julia> k = 50:100;
159-
160-
julia> s1 = sort(x; alg=QuickSort);
161-
162-
julia> s2 = sort(x; alg=PartialQuickSort(k));
163-
164-
julia> map(issorted, (s1, s2))
165-
(true, false)
166-
167-
julia> map(x->issorted(x[k]), (s1, s2))
168-
(true, true)
169-
170-
julia> s1[k] == s2[k]
171-
true
172-
```
173-
174-
!!! compat "Julia 1.9"
175-
The `QuickSort` and `PartialQuickSort` algorithms are stable since Julia 1.9.
176-
177-
`MergeSort` is an O(n log n) stable sorting algorithm but is not in-place – it requires a temporary
178-
array of half the size of the input array – and is typically not quite as fast as `QuickSort`.
179-
It is the default algorithm for non-numeric data.
180-
181-
The default sorting algorithms are chosen on the basis that they are fast and stable.
182-
Usually, `QuickSort` is selected, but `InsertionSort` is preferred for small data.
183-
You can also explicitly specify your preferred algorithm, e.g.
184-
`sort!(v, alg=PartialQuickSort(10:20))`.
185-
186-
The mechanism by which Julia picks default sorting algorithms is implemented via the
187-
`Base.Sort.defalg` function. It allows a particular algorithm to be registered as the
188-
default in all sorting functions for specific arrays. For example, here is the default
189-
method from [`sort.jl`](https://github.com/JuliaLang/julia/blob/master/base/sort.jl):
190-
191-
```julia
192-
defalg(v::AbstractArray) = DEFAULT_STABLE
193-
```
194-
195-
You may change the default behavior for specific types by defining new methods for `defalg`.
152+
You can explicitly specify your preferred algorithm with the `alg` keyword
153+
(e.g. `sort!(v, alg=PartialQuickSort(10:20))`) or reconfigure the default sorting algorithm
154+
for custom types by adding a specialized method to the `Base.Sort.defalg` function.
196155
For example, [InlineStrings.jl](https://github.com/JuliaStrings/InlineStrings.jl/blob/v1.3.2/src/InlineStrings.jl#L903)
197156
defines the following method:
198157
```julia
199158
Base.Sort.defalg(::AbstractArray{<:Union{SmallInlineStrings, Missing}}) = InlineStringSort
200159
```
201160

202161
!!! compat "Julia 1.9"
203-
The default sorting algorithm (returned by `Base.Sort.defalg`) is guaranteed
204-
to be stable since Julia 1.9. Previous versions had unstable edge cases when sorting numeric arrays.
162+
The default sorting algorithm (returned by `Base.Sort.defalg`) is guaranteed to
163+
be stable since Julia 1.9. Previous versions had unstable edge cases when
164+
sorting numeric arrays.
205165

206166
## Alternate orderings
207167

0 commit comments

Comments
 (0)