public void SearchTest() { var numbers = new [] { -10, -8, 0, 10, 500 }; var indexerDelegates = new IndexerDelegates <int, int>(index => numbers[index], index => index); // Object found. BinarySearchResult <int> result = BinarySearch <int, int> .Search(0, numbers.GetIndexInterval(), indexerDelegates); Assert.AreEqual(true, result.IsObjectFound); Assert.AreEqual(true, result.IsObjectInRange); Assert.AreEqual(0, result.Found.Object); Assert.IsNull(result.NotFound); // Object found, border. result = BinarySearch <int, int> .Search(500, numbers.GetIndexInterval(), indexerDelegates); Assert.AreEqual(true, result.IsObjectFound); Assert.AreEqual(true, result.IsObjectInRange); Assert.AreEqual(500, result.Found.Object); Assert.IsNull(result.NotFound); // Object not found, but in range. result = BinarySearch <int, int> .Search(-9, numbers.GetIndexInterval(), indexerDelegates); Assert.AreEqual(false, result.IsObjectFound); Assert.AreEqual(true, result.IsObjectInRange); Assert.AreEqual(-10, result.NotFound.Smaller); Assert.AreEqual(-8, result.NotFound.Bigger); Assert.IsNull(result.Found); // Object not found, out of range, left. result = BinarySearch <int, int> .Search(-20, numbers.GetIndexInterval(), indexerDelegates); Assert.AreEqual(false, result.IsObjectFound); Assert.AreEqual(false, result.IsObjectInRange); Assert.IsNull(result.NotFound); Assert.IsNull(result.Found); // Object not found, out of range, right. result = BinarySearch <int, int> .Search(600, numbers.GetIndexInterval(), indexerDelegates); Assert.AreEqual(false, result.IsObjectFound); Assert.AreEqual(false, result.IsObjectInRange); Assert.IsNull(result.NotFound); Assert.IsNull(result.Found); }
public void SearchTest() { var numbers = new [] { -10, -8, 0, 10, 500 }; var indexerDelegates = new IndexerDelegates<int, int>( index => numbers[ index ], index => index ); // Object found. BinarySearchResult<int> result = BinarySearch<int, int>.Search( 0, numbers.GetIndexInterval(), indexerDelegates ); Assert.AreEqual( true, result.IsObjectFound ); Assert.AreEqual( true, result.IsObjectInRange ); Assert.AreEqual( 0, result.Found.Object ); Assert.IsNull( result.NotFound ); // Object found, border. result = BinarySearch<int, int>.Search( 500, numbers.GetIndexInterval(), indexerDelegates ); Assert.AreEqual( true, result.IsObjectFound ); Assert.AreEqual( true, result.IsObjectInRange ); Assert.AreEqual( 500, result.Found.Object ); Assert.IsNull( result.NotFound ); // Object not found, but in range. result = BinarySearch<int, int>.Search( -9, numbers.GetIndexInterval(), indexerDelegates ); Assert.AreEqual( false, result.IsObjectFound ); Assert.AreEqual( true, result.IsObjectInRange ); Assert.AreEqual( -10, result.NotFound.Smaller ); Assert.AreEqual( -8, result.NotFound.Bigger ); Assert.IsNull( result.Found ); // Object not found, out of range, left. result = BinarySearch<int, int>.Search( -20, numbers.GetIndexInterval(), indexerDelegates ); Assert.AreEqual( false, result.IsObjectFound ); Assert.AreEqual( false, result.IsObjectInRange ); Assert.IsNull( result.NotFound ); Assert.IsNull( result.Found ); // Object not found, out of range, right. result = BinarySearch<int, int>.Search( 600, numbers.GetIndexInterval(), indexerDelegates ); Assert.AreEqual( false, result.IsObjectFound ); Assert.AreEqual( false, result.IsObjectInRange ); Assert.IsNull( result.NotFound ); Assert.IsNull( result.Found ); }
/// <summary> /// Searches for the given object. /// </summary> /// <param name = "toFind">The object to search for.</param> /// <param name = "range">The range in which to search.</param> /// <param name = "indexOperations">Operations that can be done on an indexer.</param> /// <returns>The found object, or it's nearest matches.</returns> public static BinarySearchResult <TObject> Search( TObject toFind, Interval <TIndex> range, IndexerDelegates <TObject, TIndex> indexOperations) { // Make sure start and end of range are valid. // TODO: This is only necessary the first call of the recursion. Implementing the search as a loop could be more performant. range = new Interval <TIndex>( indexOperations.GetNearestIndex(range.Start), indexOperations.GetNearestIndex(range.End)); // Get object near the center of the range. TIndex center = indexOperations.GetNearestIndex(range.Center); TObject centerObject = indexOperations.GetByIndex(center); // Check whether desired object was found. int orderToCenter = toFind.CompareTo(centerObject); // See whether finished. bool isObjectFound = orderToCenter == 0; bool hasNoMoreObjects = IndexComparer.Equals(center, range.Start) || IndexComparer.Equals(center, range.End); bool isFinished = isObjectFound || hasNoMoreObjects; if (!isFinished) { // Split interval in the middle. Interval <TIndex> smaller, bigger; range.Split(center, SplitOption.Both, out smaller, out bigger); // Continue recursively in the range in which the object lies. Interval <TIndex> inRange = orderToCenter > 0 ? bigger : smaller; return(Search(toFind, inRange, indexOperations)); } else { TObject smaller = indexOperations.GetByIndex(range.Start); TObject bigger = indexOperations.GetByIndex(range.End); // Find the desired object. TObject foundObject = default(TObject); if (isObjectFound) { foundObject = centerObject; } else { if (toFind.CompareTo(smaller) == 0) { isObjectFound = true; foundObject = smaller; } else if (toFind.CompareTo(bigger) == 0) { isObjectFound = true; foundObject = bigger; } } // Return result. bool isObjectInRange = toFind.CompareTo(smaller) >= 0 && toFind.CompareTo(bigger) <= 0; return(new BinarySearchResult <TObject> { IsObjectInRange = isObjectInRange, IsObjectFound = isObjectFound, Found = isObjectFound ? new BinarySearchResult <TObject> .FoundResult(foundObject) : null, NotFound = isObjectFound || !isObjectInRange ? null : new BinarySearchResult <TObject> .NotFoundResult(smaller, bigger) }); } }