using System;
using System.Collections.Generic;
namespace Algorithms.Search
{
/// <summary>
/// RecursiveBinarySearcher.
/// </summary>
/// <typeparam name="T">Type of searcher target.</typeparam>
public class RecursiveBinarySearcher<T> where T : IComparable<T>
{
/// <summary>
/// Finds index of item in collection that equals to item searched for,
/// time complexity: O(log(n)),
/// space complexity: O(1),
/// where n - collection size.
/// </summary>
/// <param name="collection">Sorted collection to search in.</param>
/// <param name="item">Item to search for.</param>
/// <exception cref="ArgumentNullException">Thrown if input collection is null.</exception>
/// <returns>Index of item that equals to item searched for or -1 if none found.</returns>
public int FindIndex(IList<T>? collection, T item)
{
if (collection is null)
{
throw new ArgumentNullException(nameof(collection));
}
var leftIndex = 0;
var rightIndex = collection.Count - 1;
return FindIndex(collection, item, leftIndex, rightIndex);
}
/// <summary>
/// Finds index of item in array that equals to item searched for,
/// time complexity: O(log(n)),
/// space complexity: O(1),
/// where n - array size.
/// </summary>
/// <param name="collection">Sorted array to search in.</param>
/// <param name="item">Item to search for.</param>
/// <param name="leftIndex">Minimum search range.</param>
/// <param name="rightIndex">Maximum search range.</param>
/// <returns>Index of item that equals to item searched for or -1 if none found.</returns>
private int FindIndex(IList<T> collection, T item, int leftIndex, int rightIndex)
{
if (leftIndex > rightIndex)
{
return -1;
}
var middleIndex = leftIndex + (rightIndex - leftIndex) / 2;
var result = item.CompareTo(collection[middleIndex]);
return result switch
{
var r when r == 0 => middleIndex,
var r when r > 0 => FindIndex(collection, item, middleIndex + 1, rightIndex),
var r when r < 0 => FindIndex(collection, item, leftIndex, middleIndex - 1),
_ => -1,
};
}
}
}