forked from TheAlgorithms/Lua
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add generic sorting algorithm stabilization
- Loading branch information
Showing
3 changed files
with
91 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
describe("Sorting stabilization", function() | ||
local stabilize = require("sorting.stabilize") | ||
local quicksort = require("sorting.quicksort") | ||
local stabilized_quicksort = stabilize(quicksort()) -- random quicksort | ||
local is_sorted = require("sorting.is_sorted") | ||
|
||
-- Sort by the first element (= value) of the pair | ||
local function comparator(a, b) | ||
return a[1] < b[1] | ||
end | ||
|
||
-- Verifies whether the sort is stable by checking results (stored as the second element of the pair) | ||
local function verifying_comparator(a, b) | ||
if a[1] == b[1] then | ||
return a[2] < b[2] | ||
end | ||
return a[1] < b[1] | ||
end | ||
|
||
it("should fail if not stabilized and work if stabilized", function() | ||
-- Inefficient but deterministic quicksort which can be used to ensure instable sorting | ||
local bad_quicksort = quicksort(function(i, _) | ||
return i | ||
end) | ||
local list = { { 1, 1 }, { 2, 2 }, { 1, 3 } } | ||
bad_quicksort(list, comparator) | ||
assert.falsy(is_sorted(list, verifying_comparator)) | ||
list = { { 1, 1 }, { 2, 2 }, { 1, 3 } } | ||
stabilize(bad_quicksort)(list, comparator) | ||
assert.truthy(is_sorted(list, verifying_comparator)) | ||
end) | ||
|
||
it("should handle edge cases", function() | ||
local list = {} | ||
stabilized_quicksort(list) | ||
assert.same({}, list) | ||
list = { 1 } | ||
stabilized_quicksort(list) | ||
assert.same({ 1 }, list) | ||
end) | ||
|
||
it("should sort random lists", function() | ||
for _ = 1, 100 do | ||
local list = {} | ||
for index = 1, 100 do | ||
list[index] = { math.random(20), index } | ||
end | ||
stabilized_quicksort(list, comparator) | ||
assert.truthy(is_sorted(list, verifying_comparator)) | ||
end | ||
end) | ||
end) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
-- Stabilizes any sorting algorithm, using linear auxiliary space (for the indices) per sorting | ||
return function( | ||
sort -- function(list, less_than) | ||
) | ||
-- stabilized sorting function | ||
return function(list, less_than) | ||
less_than = less_than or function(a, b) | ||
return a < b | ||
end | ||
-- Build a list of indices | ||
local indices = {} | ||
for index = 1, #list do | ||
indices[index] = index | ||
end | ||
-- Sort the list of indices according to values; compare indices only if they have the same value | ||
sort(indices, function(index_a, index_b) | ||
if less_than(list[index_a], list[index_b]) then | ||
return true | ||
end | ||
if less_than(list[index_b], list[index_a]) then | ||
return false | ||
end | ||
return index_a < index_b | ||
end) | ||
-- Map indices to values | ||
for index = 1, #list do | ||
indices[index] = list[indices[index]] | ||
end | ||
-- Replace elements in original list (sorting is supposed to be in-place) | ||
for index = 1, #list do | ||
list[index] = indices[index] | ||
end | ||
end | ||
end |