diff --git a/search/binary_search.ts b/search/binary_search.ts index 39d380a4..cf86f39a 100644 --- a/search/binary_search.ts +++ b/search/binary_search.ts @@ -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 @@ -37,7 +37,7 @@ 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 = ( @@ -45,16 +45,16 @@ export const binarySearchRecursive = ( 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 diff --git a/search/exponential_search.ts b/search/exponential_search.ts new file mode 100644 index 00000000..4a8eba47 --- /dev/null +++ b/search/exponential_search.ts @@ -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 +} diff --git a/search/test/binary_search.test.ts b/search/test/binary_search.test.ts index 6ebd12d9..13b13251 100644 --- a/search/test/binary_search.test.ts +++ b/search/test/binary_search.test.ts @@ -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 @@ -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) diff --git a/search/test/exponential_search.test.ts b/search/test/exponential_search.test.ts new file mode 100644 index 00000000..80f6a07f --- /dev/null +++ b/search/test/exponential_search.test.ts @@ -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) + } + ) +})