[algo] Add stable sort algorithm, using merge sort.

This commit is contained in:
Lorenzo Cogotti 2023-06-01 22:44:27 +02:00
parent c58edfa486
commit d3129070d9
1 changed files with 70 additions and 0 deletions

View File

@ -139,4 +139,74 @@ function algo.bsearchr(array, what, less)
return lo + ofs
end
local function merge(array, lo, mid, hi, less, workspace)
local i, j, k
i = 1
-- Copy first half of array to auxiliary array
for j = lo,mid do
workspace[i] = array[j]
i = i + 1
end
i = 1
j = mid + 1
k = lo
while k < j and j <= hi do
local v = array[j]
local el = workspace[i]
if less(v, el) then
array[k] = v
j = j + 1
else
array[k] = el
i = i + 1
end
k = k + 1
end
-- Copy back any remaining elements of first half
for k = k,j-1 do
array[k] = workspace[i]
i = i + 1
end
end
local function mergesort(array, lo, hi, less, workspace)
if hi - lo < 72 then
_insertionsort(array, lo, hi, less)
else
local mid = floor((lo + hi)/2)
mergesort(array, lo, mid, less, workspace)
mergesort(array, mid + 1, hi, less, workspace)
merge(array, lo, mid, hi, less, workspace)
end
end
--- Array stable sort, uses Merge Sort - O(n*log(n)).
--
-- Algorithm is a slightly altered version of stable_sort(),
-- posted on Lua-L by Steve Fisher on 02 May 2013 22:10:50
-- https://lua-users.org/lists/lua-l/2013-05/msg00038.html
--
-- This implementation uses an auxiliary buffer of size O(n/2).
--
-- @tparam table array Array to be sorted.
-- @tparam[opt=operator <] function less comparison function, takes 2 arguments,
-- returns true if its first argument is
-- less than its second argument,
-- false otherwise.
-- @tparam[opt={}] table use an existing workspace buffer instead of allocating one.
function algo.stablesort(array, less, workspace)
local n = #array
less = less or lt
workspace = workspace or {}
workspace[floor((n+1)/2)] = array[1] -- preallocate some room
mergesort(array, 1, n, less, workspace)
end
return algo