Skip to content

Commit

Permalink
Exponential search (#247)
Browse files Browse the repository at this point in the history
* feat: add exponential search

* test: add test for exponential search

* fix : prettier fix

* fix: added parameters to iterative binary search

* fix: prettier fix #2

* fix: modified the return on binary search and related tests
  • Loading branch information
Fechuli authored Aug 5, 2024
1 parent e6d916e commit 44127b2
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 23 deletions.
32 changes: 16 additions & 16 deletions search/binary_search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,25 @@
*
* @param {number[]} array - sorted list of numbers
* @param {number} target - target number to search for
* @return {number} - index of the target number in the list, or -1 if not found
* @return {number} - index of the target number in the list, or null if not found
* @see [BinarySearch](https://www.geeksforgeeks.org/binary-search/)
* @example binarySearch([1,2,3], 2) => 1
* @example binarySearch([4,5,6], 2) => -1
* @example binarySearch([4,5,6], 2) => null
*/

export const binarySearchIterative = (
array: number[],
target: number
): number => {
if (array.length === 0) return -1

// declare pointers for the start, middle and end indices
let start = 0,
end = array.length - 1,
middle = (start + end) >> 1
target: number,
start: number = 0,
end: number = array.length - 1
): number | null => {
if (array.length === 0) return null

// ensure the target is within the bounds of the array
if (target < array[start] || target > array[end]) return -1
if (target < array[start] || target > array[end]) return null

// declare pointers for the middle index
let middle = (start + end) >> 1

while (array[middle] !== target && start <= end) {
// if the target is less than the middle value, move the end pointer to be middle -1 to narrow the search space
Expand All @@ -37,24 +37,24 @@ export const binarySearchIterative = (
middle = (start + end) >> 1
}
// return the middle index if it is equal to target
return array[middle] === target ? middle : -1
return array[middle] === target ? middle : null
}

export const binarySearchRecursive = (
array: number[],
target: number,
start = 0,
end = array.length - 1
): number => {
if (array.length === 0) return -1
): number | null => {
if (array.length === 0) return null

// ensure the target is within the bounds of the array
if (target < array[start] || target > array[end]) return -1
if (target < array[start] || target > array[end]) return null

const middle = (start + end) >> 1

if (array[middle] === target) return middle // target found
if (start > end) return -1 // target not found
if (start > end) return null // target not found

// if the target is less than the middle value, move the end pointer to be middle -1 to narrow the search space
// otherwise, move the start pointer to be middle + 1
Expand Down
40 changes: 40 additions & 0 deletions search/exponential_search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { binarySearchIterative } from './binary_search'

/**
* @description Exponential search algorithm for a sorted array.
*
* The algorithm searches for a specific value in a sorted array by first finding a range
* where the value may be present and then performing a binary search within that range.
*
* Compared with binary search, exponential search can be more convenient and advantageous
* in cases where the element to be searched is closer to the beginning of the array,
* thus avoiding several comparisons that would make the search more verbose.
*
* @param {number[]} array - sorted list of numbers
* @param {number} x - target number to search for
* @return {number | null} - index of the target number in the list, or null if not found
* @see [ExponentialSearch](https://www.geeksforgeeks.org/exponential-search/)
* @example exponentialSearch([1, 2, 3, 4, 5], 3) => 2
* @example exponentialSearch([10, 20, 30, 40, 50], 35) => null
*/

export const exponentialSearch = (
array: number[],
x: number
): number | null => {
const arrayLength = array.length
if (arrayLength === 0) return null

if (array[0] === x) return 0

let i = 1
while (i < arrayLength && array[i] <= x) {
i = i * 2
}

const start = Math.floor(i / 2)
const end = Math.min(i, arrayLength - 1)
const result = binarySearchIterative(array, x, start, end)

return result
}
16 changes: 9 additions & 7 deletions search/test/binary_search.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { binarySearchIterative, binarySearchRecursive } from '../binary_search'

describe('BinarySearch', () => {
const testArray: number[] = [1, 2, 3, 4]
type FunctionsArray = { (array: number[], index: number): number }[]
type FunctionsArray = { (array: number[], index: number): number | null }[]
const functions: FunctionsArray = [
binarySearchIterative,
binarySearchRecursive
Expand All @@ -12,14 +12,16 @@ describe('BinarySearch', () => {
it('should be defined', () => {
expect(func(testArray, 2)).toBeDefined()
})
it('should return a number', () => {
expect(typeof func(testArray, 2)).toBe('number')
it('should return a number or null', () => {
expect(
typeof func(testArray, 2) === 'number' || func(testArray, 2) === null
).toBe(true)
})
it('should return -1 if the target is not found in the array', () => {
expect(func(testArray, 5)).toBe(-1)
it('should return null if the target is not found in the array', () => {
expect(func(testArray, 5)).toBe(null)
})
it('should return -1 if there are no elements in the array', () => {
expect(func([], 5)).toBe(-1)
it('should return null if there are no elements in the array', () => {
expect(func([], 5)).toBe(null)
})
it('should return the index of the target if it is found in the array', () => {
expect(func(testArray, 2)).toBe(1)
Expand Down
19 changes: 19 additions & 0 deletions search/test/exponential_search.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { exponentialSearch } from '../exponential_search'

describe('Exponential search', () => {
test.each([
[[1, 2, 3, 4, 5], 3, 2],
[[10, 20, 30, 40, 50], 35, null],
[[10, 20, 30, 40, 50], 10, 0],
[[10, 20, 30, 40, 50], 50, 4],
[[10, 20, 30, 40, 50], 60, null],
[[], 10, null],
[[1, 2, 3, 4, 5], 1, 0],
[[1, 2, 3, 4, 5], 5, 4]
])(
'of %o, searching for %o, expected %i',
(array: number[], target: number, expected: number | null) => {
expect(exponentialSearch(array, target)).toBe(expected)
}
)
})

0 comments on commit 44127b2

Please sign in to comment.