-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
BinarySearch function has two signatures: - `int index BinarySearch(number key, table array, string approximation)` - `int index BinarySearch(number key, int low, int high, function getValue)` getValue is a function with the signature: - `number value getValue(int index)` Given that all values in the array (or returned by getValue by index) are in ascending order; BinarySearch will find the index of the value `key` being searched for, or nil if none are found. The string `approximation` can be set to the following: - `nil`: If not set, only exact matches will be returned. - `nearest`: The array index with the closest value will be returned. - `up`: Nearest value, but always rounding up if possible. - `down`: Nearest value, but always rounding down if possible.
- Loading branch information
1 parent
71800fe
commit 53e69e7
Showing
9 changed files
with
1,047 additions
and
2 deletions.
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
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,68 @@ | ||
|
||
local array_mt = { | ||
__index = function(self, key) | ||
return self.__getValue(key) | ||
end | ||
} | ||
|
||
function BinarySearch(key, array, approximation, arg4, arg5) | ||
local low, high | ||
|
||
if type(array) == 'table' then | ||
low, high = 1, #array | ||
else | ||
local getValue | ||
|
||
-- Pass over variables from alternate signature. | ||
key, low, high, getValue, approximation = key, array, approximation, arg4, arg5 | ||
|
||
array = { __getValue = getValue } | ||
setmetatable(array, array_mt) | ||
end | ||
|
||
if high <= low then | ||
return nil | ||
end | ||
|
||
-- Run binary search until there are 2 or fewer values left. | ||
while high - low > 1 do | ||
local mid = math.floor((low + high) / 2) | ||
local val = array[mid] | ||
|
||
if key > val then | ||
low = mid | ||
else | ||
high = mid | ||
end | ||
end | ||
|
||
-- There are only 1 or 2 values left, 'low' and 'high'. | ||
if approximation == "nearest" then | ||
local low_diff = math.abs(key - array[low]) | ||
local high_diff = math.abs(key - array[high]) | ||
|
||
if low_diff < high_diff then | ||
return low | ||
else | ||
return high | ||
end | ||
elseif approximation == "up" then | ||
if key > array[low] then | ||
return high | ||
else | ||
return low | ||
end | ||
elseif approximation == "down" then | ||
if key < array[high] then | ||
return low | ||
else | ||
return high | ||
end | ||
else | ||
if key == array[low] then | ||
return low | ||
elseif key == array[high] then | ||
return high | ||
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
local testsuite = Tests.Testsuite() | ||
testsuite.name = "BinarySearch tests" | ||
|
||
local TEXT_ERROR = "Returned index of binary search for %s" | ||
|
||
local function err(key) | ||
return string.format(TEXT_ERROR, key) | ||
end | ||
|
||
function testsuite.test_binary_search_exact() | ||
local array = {10, 20, 30} | ||
|
||
Assert.Equals(1, BinarySearch(10, array), err("value 10")) | ||
Assert.Equals(2, BinarySearch(20, array), err("value 20")) | ||
Assert.Equals(3, BinarySearch(30, array), err("value 30")) | ||
Assert.Equals(nil, BinarySearch(0, array), err("value 0")) | ||
Assert.Equals(nil, BinarySearch(19, array), err("value 19")) | ||
Assert.Equals(nil, BinarySearch(21, array), err("value 21")) | ||
Assert.Equals(nil, BinarySearch(40, array), err("value 40")) | ||
|
||
return true | ||
end | ||
|
||
function testsuite.test_binary_search_nearest() | ||
local array = {10, 20, 30} | ||
|
||
Assert.Equals(1, BinarySearch(10, array, "nearest"), err("value 10")) | ||
Assert.Equals(2, BinarySearch(20, array, "nearest"), err("value 20")) | ||
Assert.Equals(3, BinarySearch(30, array, "nearest"), err("value 30")) | ||
Assert.Equals(1, BinarySearch(0, array, "nearest"), err("value 0")) | ||
Assert.Equals(2, BinarySearch(19, array, "nearest"), err("value 19")) | ||
Assert.Equals(2, BinarySearch(21, array, "nearest"), err("value 21")) | ||
Assert.Equals(3, BinarySearch(40, array, "nearest"), err("value 40")) | ||
|
||
return true | ||
end | ||
|
||
function testsuite.test_binary_search_up() | ||
local array = {10, 20, 30} | ||
|
||
Assert.Equals(1, BinarySearch(10, array, "up"), err("value 10")) | ||
Assert.Equals(2, BinarySearch(20, array, "up"), err("value 20")) | ||
Assert.Equals(3, BinarySearch(30, array, "up"), err("value 30")) | ||
Assert.Equals(1, BinarySearch(0, array, "up"), err("value 0")) | ||
Assert.Equals(2, BinarySearch(19, array, "up"), err("value 19")) | ||
Assert.Equals(3, BinarySearch(21, array, "up"), err("value 21")) | ||
Assert.Equals(3, BinarySearch(40, array, "up"), err("value 40")) | ||
|
||
return true | ||
end | ||
|
||
function testsuite.test_binary_search_down() | ||
local array = {10, 20, 30} | ||
|
||
Assert.Equals(1, BinarySearch(10, array, "down"), err("value 10")) | ||
Assert.Equals(2, BinarySearch(20, array, "down"), err("value 20")) | ||
Assert.Equals(3, BinarySearch(30, array, "down"), err("value 30")) | ||
Assert.Equals(1, BinarySearch(0, array, "down"), err("value 0")) | ||
Assert.Equals(1, BinarySearch(19, array, "down"), err("value 19")) | ||
Assert.Equals(2, BinarySearch(21, array, "down"), err("value 21")) | ||
Assert.Equals(3, BinarySearch(40, array, "down"), err("value 40")) | ||
|
||
return true | ||
end | ||
|
||
function testsuite.test_binary_search_noarray_exact() | ||
local array = {10, 20, 30} | ||
local low, high = 1, #array | ||
|
||
local function getValue(key) | ||
return array[key] | ||
end | ||
|
||
Assert.Equals(1, BinarySearch(10, low, high, getValue), err("value 10")) | ||
Assert.Equals(2, BinarySearch(20, low, high, getValue), err("value 20")) | ||
Assert.Equals(3, BinarySearch(30, low, high, getValue), err("value 30")) | ||
Assert.Equals(nil, BinarySearch(0, low, high, getValue), err("value 0")) | ||
Assert.Equals(nil, BinarySearch(19, low, high, getValue), err("value 19")) | ||
Assert.Equals(nil, BinarySearch(21, low, high, getValue), err("value 21")) | ||
Assert.Equals(nil, BinarySearch(40, low, high, getValue), err("value 40")) | ||
|
||
return true | ||
end | ||
|
||
function testsuite.test_binary_search_noarray_nearest() | ||
local array = {10, 20, 30} | ||
local low, high = 1, #array | ||
|
||
local function getValue(key) | ||
return array[key] | ||
end | ||
|
||
Assert.Equals(1, BinarySearch(10, low, high, getValue, "nearest"), err("value 10")) | ||
Assert.Equals(2, BinarySearch(20, low, high, getValue, "nearest"), err("value 20")) | ||
Assert.Equals(3, BinarySearch(30, low, high, getValue, "nearest"), err("value 30")) | ||
Assert.Equals(1, BinarySearch(0, low, high, getValue, "nearest"), err("value 0")) | ||
Assert.Equals(2, BinarySearch(19, low, high, getValue, "nearest"), err("value 19")) | ||
Assert.Equals(2, BinarySearch(21, low, high, getValue, "nearest"), err("value 21")) | ||
Assert.Equals(3, BinarySearch(40, low, high, getValue, "nearest"), err("value 40")) | ||
|
||
return true | ||
end | ||
|
||
function testsuite.test_binary_search_noarray_up() | ||
local array = {10, 20, 30} | ||
local low, high = 1, #array | ||
|
||
local function getValue(key) | ||
return array[key] | ||
end | ||
|
||
Assert.Equals(1, BinarySearch(10, low, high, getValue, "up"), err("value 10")) | ||
Assert.Equals(2, BinarySearch(20, low, high, getValue, "up"), err("value 20")) | ||
Assert.Equals(3, BinarySearch(30, low, high, getValue, "up"), err("value 30")) | ||
Assert.Equals(1, BinarySearch(0, low, high, getValue, "up"), err("value 0")) | ||
Assert.Equals(2, BinarySearch(19, low, high, getValue, "up"), err("value 19")) | ||
Assert.Equals(3, BinarySearch(21, low, high, getValue, "up"), err("value 21")) | ||
Assert.Equals(3, BinarySearch(40, low, high, getValue, "up"), err("value 40")) | ||
|
||
return true | ||
end | ||
|
||
function testsuite.test_binary_search_noarray_down() | ||
local array = {10, 20, 30} | ||
local low, high = 1, #array | ||
|
||
local function getValue(key) | ||
return array[key] | ||
end | ||
|
||
Assert.Equals(1, BinarySearch(10, low, high, getValue, "down"), err("value 10")) | ||
Assert.Equals(2, BinarySearch(20, low, high, getValue, "down"), err("value 20")) | ||
Assert.Equals(3, BinarySearch(30, low, high, getValue, "down"), err("value 30")) | ||
Assert.Equals(1, BinarySearch(0, low, high, getValue, "down"), err("value 0")) | ||
Assert.Equals(1, BinarySearch(19, low, high, getValue, "down"), err("value 19")) | ||
Assert.Equals(2, BinarySearch(21, low, high, getValue, "down"), err("value 21")) | ||
Assert.Equals(3, BinarySearch(40, low, high, getValue, "down"), err("value 40")) | ||
|
||
return true | ||
end | ||
|
||
return testsuite |
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
Oops, something went wrong.