diff --git a/algo.lua b/algo.lua index 898bf8f..ff0e4d4 100644 --- a/algo.lua +++ b/algo.lua @@ -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