Skip to content

Commit

Permalink
Add search algorithm FastSearch (TheAlgorithms#123)
Browse files Browse the repository at this point in the history
* Add search algorithm FastSearch

* Add a link to FastSearch algorithm to README.md

* Add tests for FastSearch algorithm

* Pass array as a parameter, not as a field in FastSearch (thread-safe)

* Improved tests for FastSearch

* Removed repetitive code in FastSearch

* fixed formatting in Algorithms.Tests/Search/FastSearcherTests.cs

Co-Authored-By: Andrii Siriak <[email protected]>

* Fixed Assert.Throws

Co-Authored-By: Andrii Siriak <[email protected]>

* Add using Utility.Exception

* Fixed Assert.Throws in Algorithms.Tests\Search\LinearSearcherTests.cs

* Removed redundant sort and changed int to var in for loop

* removed unused using System.Linq

* Add test-case for divided by zero prevention

* Add tests

* Fix indices

* Add Helper class

* Cover edge cases

* Add more tests

* Add LF

Co-authored-by: Andrii Siriak <[email protected]>
  • Loading branch information
Gökhan Witteborn-Demir and siriak committed Dec 31, 2019
1 parent 9c6f3d6 commit 0bbed07
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 0 deletions.
65 changes: 65 additions & 0 deletions Algorithms.Tests/Search/FastSearcherTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using Algorithms.Search;
using NUnit.Framework;
using Utilities.Exceptions;

namespace Algorithms.Tests.Search
{
public static class FastSearcherTests
{
[Test]
public static void FindIndex_ItemPresent_IndexCorrect()
{
var searcher = new FastSearcher();
var arr = Helper.GetSortedArray(1000);
var present = Helper.GetItemIn(arr);
var index = searcher.FindIndex(arr, present);
Assert.AreEqual(present, arr[index]);
}

[Test]
public static void FindIndex_ItemMissing_ItemNotFoundExceptionThrown()
{
var searcher = new FastSearcher();
var arr = Helper.GetSortedArray(1000);
var missing = Helper.GetItemNotIn(arr);
_ = Assert.Throws<ItemNotFoundException>(() => searcher.FindIndex(arr, missing));
}

[Test]
public static void FindIndex_ItemSmallerThanAllMissing_ItemNotFoundExceptionThrown()
{
var searcher = new FastSearcher();
var arr = Helper.GetSortedArray(1000);
var missing = Helper.GetItemSmallerThanAllIn(arr);
_ = Assert.Throws<ItemNotFoundException>(() => searcher.FindIndex(arr, missing));
}

[Test]
public static void FindIndex_ItemBiggerThanAllMissing_ItemNotFoundExceptionThrown()
{
var searcher = new FastSearcher();
var arr = Helper.GetSortedArray(1000);
var missing = Helper.GetItemBiggerThanAllIn(arr);
_ = Assert.Throws<ItemNotFoundException>(() => searcher.FindIndex(arr, missing));
}

[Test]
public static void FindIndex_ArrayOfDuplicatesItemPresent_IndexCorrect()
{
var searcher = new FastSearcher();
var arr = new int[1000];
var present = 0;
var index = searcher.FindIndex(arr, present);
Assert.AreEqual(0, arr[index]);
}

[Test]
public static void FindIndex_ArrayOfDuplicatesItemMissing_ItemNotFoundExceptionThrown()
{
var searcher = new FastSearcher();
var arr = new int[1000];
var missing = 1;
_ = Assert.Throws<ItemNotFoundException>(() => searcher.FindIndex(arr, missing));
}
}
}
27 changes: 27 additions & 0 deletions Algorithms.Tests/Search/Helper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Linq;
using NUnit.Framework;

namespace Algorithms.Tests.Search
{
public static class Helper
{
public static int[] GetSortedArray(int length) => Enumerable.Range(0, length).Select(x => TestContext.CurrentContext.Random.Next(1_000_000)).OrderBy(x => x).ToArray();

public static int GetItemIn(int[] arr) => arr[TestContext.CurrentContext.Random.Next(arr.Length)];

public static int GetItemNotIn(int[] arr)
{
int item;
do
{
item = TestContext.CurrentContext.Random.Next(arr.Min(), arr.Max() + 1);
} while (arr.Contains(item));

return item;
}

public static int GetItemSmallerThanAllIn(int[] arr) => arr.Min() - 1;

public static int GetItemBiggerThanAllIn(int[] arr) => arr.Max() + 1;
}
}
91 changes: 91 additions & 0 deletions Algorithms/Search/FastSearcher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System;
using Utilities.Exceptions;

namespace Algorithms.Search
{
/// <summary>
/// The idea: you could combine the advantages from both binary-search and interpolation search algorithm.
/// Time complexity:
/// worst case: Item couldn't be found: O(log n),
/// average case: O(log log n),
/// best case: O(1).
/// Note: This algorithm is recursive and the array has to be sorted beforehand.
/// </summary>
public class FastSearcher
{
/// <summary>
/// Finds index of first item in array that satisfies specified term
/// throws ItemNotFoundException if the item couldn't be found.
/// </summary>
/// <param name="array">Span of sorted numbers which will be used to find the item.</param>
/// <param name="item">Term to check against.</param>
/// <returns>Index of first item that satisfies term.</returns>
/// <exception cref="ItemNotFoundException"> Gets thrown when the given item couldn't be found in the array.</exception>
public int FindIndex(int[] array, int item) => FindIndex(array, item, 0);

private int FindIndex(int[] array, int item, int offset)
{
if (array[0] == array[array.Length - 1])
{
return item == array[0] ? offset : throw new ItemNotFoundException();
}

var indexBinary = array.Length / 2;

int[] section =
{
array.Length - 1,
item - array[0],
array[array.Length - 1] - array[0],
};

var indexInterpolation = section[0] * section[1] / section[2];

if (indexInterpolation >= array.Length)
{
throw new ItemNotFoundException();
}

if (indexBinary > indexInterpolation)
{
(indexBinary, indexInterpolation) = (indexInterpolation, indexBinary);
}

int from, to;
if (item == array[indexBinary])
{
return offset + indexBinary;
}

if (item == array[indexInterpolation])
{
return offset + indexInterpolation;
}

if (item < array[indexBinary])
{
@from = 0;
to = indexBinary - 1;
}
else if (item < array[indexInterpolation])
{
@from = indexBinary + 1;
to = indexInterpolation - 1;
}
else
{
@from = indexInterpolation + 1;
to = array.Length - 1;
}

if (from >= to)
{
throw new ItemNotFoundException();
}

var segment = new int[to - from + 1];
Array.Copy(array, from, segment, 0, segment.Length);
return FindIndex(segment, item, offset + from);
}
}
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ This repository contains algorithms and data structures implemented in C# for ed
* [A-Star](./Algorithms/Search/AStar/)
* [Binary](./Algorithms/Search/BinarySearcher.cs)
* [Linear](./Algorithms/Search/LinearSearcher.cs)
* [FastSearch](./Algorithms/Search/FastSearcher.cs)
* [Sorts](./Algorithms/Sorters/)
* [Comparison](./Algorithms/Sorters/Comparison)
* [Binary Insertion](./Algorithms/Sorters/Comparison/BinaryInsertionSorter.cs)
Expand Down

0 comments on commit 0bbed07

Please sign in to comment.