KitchenSink v1.3.7 KitchenSink.Algorithms View Source
This is a collection of algorithms.
The binary search fit
function
The search is controlled by the fit
function which is passed the value to
test and returns :ok
if the value is good enough, :high
if the next
value to test should be higher, or :low
if the next value should be
lower.
Link to this section Summary
Functions
binary_search
performs a binary search over a range
Link to this section Types
binary_interval_search_fit_func() :: (binary_interval_search_position, any -> :ok | :high | :low)
binary_interval_search_position() :: number
binary_interval_search_result :: {:ok, binary_interval_search_position} | :not_found
binary_search_fit_func() :: (binary_search_position, any -> :ok | :high | :low)
binary_search_result() :: {:ok, binary_search_position} | :not_found
binary_search_strategy() :: :midpoint | :interval
Link to this section Functions
binary_search(binary_search_position, binary_search_position, binary_search_fit_func, any, binary_search_strategy) :: binary_search_result
binary_search
performs a binary search over a range.
The binary search function requires a midpoint strategy to be specified. If no strategy
is specified, it defaults to :midpoint
Examples using the :midpoint
strategy
iex> names = ~w(Adrian Bill Robert Tony) # Sorted!
iex> search_names = fn(position, target) ->
...> current = Enum.at(names, position)
...> cond do
...> current < target -> :high
...> current == target -> :ok
...> current > target -> :low
...> end
...> end
iex>
iex> Algorithms.binary_search(0, 3, search_names, "Tony", :midpoint)
{:ok, 3}
iex> Algorithms.binary_search(0, 3, search_names, "Phil", :midpoint)
{:not_found, 2}
It is possible to override the calculation of the midpoint for the binary search, and that is “…left as an exercise for the reader.”
It is also possible to binary-search multiple ranges at the same time, in case you are trying to find some balance between of a number of variable factors.
Example (albeit a contrived one) of searching multiple ranges simultaneously
iex> solve = fn (pos, desired_result) -> …> result = Enum.reduce(pos, fn (x, acc) -> x + acc end) …> cond do …> result < desired_result -> :high …> result == desired_result -> :ok …> result > desired_result -> :low …> end …> end iex> Algorithms.hybrid_binary_search([2..40, 20..100], solve, 27, :midpoint)
Examples using the :interval
strategy
To see where y = 10 + x³ and y = 1000 + x² intersect
iex> solve = fn(position, _) ->
...> y1 = 10 + :math.pow(position, 3)
...> y2 = 1000 + :math.pow(position, 2)
...> difference = y1 - y2
...>
...> epsilon = 0.0001
...>
...> cond do
...> abs(difference) < epsilon -> :ok
...> difference > 0.0 -> :low
...> difference < 0.0 -> :high
...> end
...> end
iex>
iex> {:ok, result} = Algorithms.binary_search(1, 100, solve, 0.0, :interval)
iex> Float.round(result, 6)
10.311285