ПРЕДУПРЕЖДЕНИЯ: не использовать это в производстве, это медленнее, чем простой линейный поиск, так как связанные списки не позволяют для произвольного доступа в постоянная время. Это сообщение касается всего лишь аспекта соответствия шаблону.
Теоретически вы можете использовать пункты охраны, но они могут значительно ухудшить ситуацию, если вы переусердствовали. Предполагая, что вы начинаете с реализацией, как это:
defmodule MyEnum do
def binsearch(collection, key) do
binsearch(collection, key, 1, length(collection))
end
defp binsearch(collection, key, lo, hi) do
if hi < lo do
-1
else
mid = div(lo + hi, 2)
item = Enum.at(collection, mid)
cond do
key < item -> binsearch(collection, key, lo, mid-1)
key > item -> binsearch(collection, key, mid+1, hi)
true -> mid
end
end
end
end
Может быть, вы хотите, чтобы извлечь if
в пункт охраны:
defmodule MyEnum do
def binsearch(collection, key) do
binsearch(collection, key, 1, length(collection))
end
defp binsearch(_collection, _key, lo, hi) when hi < lo do
-1
end
defp binsearch(collection, key, lo, hi) do
mid = div(lo + hi, 2)
item = Enum.at(collection, mid)
cond do
key < item -> binsearch(collection, key, lo, mid-1)
key > item -> binsearch(collection, key, mid+1, hi)
true -> mid
end
end
end
Теперь вы также можете вытащить cond
из в guard clauses, но это на самом деле не улучшение:
defmodule MyEnum do
def binsearch(collection, key) do
binsearch(collection, key, 1, length(collection))
end
defp binsearch(_collection, _key, low, hi) when hi < low do
-1
end
defp binsearch(collection, key, low, hi) do
mid = div(low + hi, 2)
item = Enum.at(collection, mid)
binsearch(collection, key, item, low, mid, hi)
end
defp binsearch(collection, key, item, low, mid, _hi) when key < item do
binsearch(collection, key, low, mid-1)
end
defp binsearch(collection, key, item, _low, mid, hi) when key > item do
binsearch(collection, key, mid+1, hi)
end
defp binsearch(_collection, _key, _item, _low, mid, _hi) do
mid
end
end
Спасибо за подробный ответ. Да, переключение cond для защитных предложений может немного усложниться. – davidcunha
Двоичный поиск эффективен только в том случае, если коллекция имеет O (1) поиск. 'Enum.at' работает в линейном времени, поэтому этот двоичный поиск медленнее, чем простой линейный поиск –
Спасибо, очень хорошая точка. Я был на своих ранних шагах с Эликсиром, когда я написал ответ и, вероятно, пропустил это, потому что я сосредоточился на сопоставлении с образцом. –