Skip to content

Commit

Permalink
Implemented CombSort as an additional sorting algorithm in base
Browse files Browse the repository at this point in the history
  • Loading branch information
nlw0 committed Jul 26, 2019
1 parent 8cc2f12 commit 91fc5a3
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 5 deletions.
1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export
Channel,
Cmd,
Colon,
CombSort,
Complex,
ComplexF64,
ComplexF32,
Expand Down
17 changes: 16 additions & 1 deletion base/ordering.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export # not exported by Base
By, Lt, Perm,
ReverseOrdering, ForwardOrdering,
DirectOrdering,
lt, ord, ordtype
lt, ltminmax, ord, ordtype

abstract type Ordering end

Expand Down Expand Up @@ -57,6 +57,21 @@ lt(o::Lt, a, b) = o.lt(a,b)
lt(p.order, da, db) | (!lt(p.order, db, da) & (a < b))
end

ltminmax(o::ForwardOrdering, a, b) = min(a,b), max(a,b)
ltminmax(o::ReverseOrdering, a, b) = max(a,b), min(a,b)
ltminmax(o::By, a, b) = ifelse(isless(o.by(a),o.by(b)), a, b), ifelse(isless(o.by(a),o.by(b)), b, a)
ltminmax(o::Lt, a, b) = ifelse(o.lt(a,b), a, b), ifelse(o.lt(a,b), b, a)

@propagate_inbounds function ltminmax(p::Perm, a::Integer, b::Integer)
da = p.data[a]
db = p.data[b]
if (lt(p.order, da, db) | (!lt(p.order, db, da) & (a < b)))
(a, b)
else
(b, a)
end
end

ordtype(o::ReverseOrdering, vs::AbstractArray) = ordtype(o.fwd, vs)
ordtype(o::Perm, vs::AbstractArray) = ordtype(o.order, o.data)
# TODO: here, we really want the return type of o.by, without calling it
Expand Down
34 changes: 33 additions & 1 deletion base/sort.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export # also exported by Base
InsertionSort,
QuickSort,
MergeSort,
CombSort,
PartialQuickSort

export # not exported by Base
Expand Down Expand Up @@ -385,6 +386,7 @@ abstract type Algorithm end
struct InsertionSortAlg <: Algorithm end
struct QuickSortAlg <: Algorithm end
struct MergeSortAlg <: Algorithm end
struct CombSortAlg <: Algorithm end

"""
PartialQuickSort{T <: Union{Int,OrdinalRange}}
Expand Down Expand Up @@ -454,6 +456,24 @@ Characteristics:
* *divide-and-conquer* sort strategy.
"""
const MergeSort = MergeSortAlg()
"""
CombSort
Indicate that a sorting function should use the comb sort
algorithm. Comb sort traverses the collection multiple times
ordering pairs of elements with a given interval between them.
The interval decreases exponentially until it becomes 1, then
it switches to insertion sort on the whole input.
Characteristics:
* *not stable*: does not preserve the ordering of elements which
compare equal (e.g. "a" and "A" in a sort of letters which
ignores case).
* *in-place* in memory.
* *parallelizable* this algorithm is suitable for vectorization
because it performs many independent comparisons.
"""
const CombSort = CombSortAlg()

const DEFAULT_UNSTABLE = QuickSort
const DEFAULT_STABLE = MergeSort
Expand Down Expand Up @@ -608,7 +628,6 @@ function sort!(v::AbstractVector, lo::Int, hi::Int, a::PartialQuickSort{Int},
return v
end


function sort!(v::AbstractVector, lo::Int, hi::Int, a::PartialQuickSort{T},
o::Ordering) where T<:OrdinalRange
@inbounds while lo < hi
Expand All @@ -632,6 +651,19 @@ function sort!(v::AbstractVector, lo::Int, hi::Int, a::PartialQuickSort{T},
return v
end

function sort!(v::AbstractVector, lo::Int, hi::Int, ::CombSortAlg, o::Ordering)
interval = (3 * (hi-lo+1)) >> 2

@inbounds while interval > 1
for j in lo:hi-interval
v[j], v[j+interval] = ltminmax(o, v[j], v[j+interval])
end
interval = (3 * interval) >> 2
end

return sort!(v, lo, hi, InsertionSort, o)
end


## generic sorting methods ##

Expand Down
6 changes: 3 additions & 3 deletions test/sorting.jl
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ Base.step(r::ConstantRange) = 0
end

@testset "unstable algorithms" begin
for alg in [QuickSort, PartialQuickSort(length(a))]
for alg in [QuickSort, PartialQuickSort(length(a)), CombSort]
b = sort(a, alg=alg)
@test issorted(b)
b = sort(a, alg=alg, rev=true)
Expand Down Expand Up @@ -265,7 +265,7 @@ end
end

# unstable algorithms
for alg in [QuickSort, PartialQuickSort(n)]
for alg in [QuickSort, PartialQuickSort(n), CombSort]
p = sortperm(v, alg=alg, rev=rev)
@test p == sortperm(float(v), alg=alg, rev=rev)
@test isperm(p)
Expand All @@ -279,7 +279,7 @@ end
end

v = randn_with_nans(n,0.1)
# TODO: alg = PartialQuickSort(n) fails here
# TODO: alg = PartialQuickSort(n) and CombSort fail here
for alg in [InsertionSort, QuickSort, MergeSort],
rev in [false,true]
# test float sorting with NaNs
Expand Down

0 comments on commit 91fc5a3

Please sign in to comment.