From 1861a8775bfebb44e88c433ed26835b17645b660 Mon Sep 17 00:00:00 2001 From: Federico Fiaschi Date: Sun, 4 Aug 2024 20:49:56 +0200 Subject: [PATCH 1/6] feat: add exponential search --- search/exponential_search.ts | 50 ++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 search/exponential_search.ts diff --git a/search/exponential_search.ts b/search/exponential_search.ts new file mode 100644 index 00000000..01c68051 --- /dev/null +++ b/search/exponential_search.ts @@ -0,0 +1,50 @@ +/** + * @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. + * + * @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; + } + + return binarySearch(array, x, i / 2, Math.min(i, arrayLength - 1)); + }; + + const binarySearch = ( + array: number[], + x: number, + start: number, + end: number + ): number | null => { + while (start <= end) { + const mid = Math.floor((start + end) / 2); + if (array[mid] === x) { + return mid; + } else if (array[mid] < x) { + start = mid + 1; + } else { + end = mid - 1; + } + } + return null; + }; + \ No newline at end of file From 5b37d3b18e70199e42bb1f435bd1fbef413839d7 Mon Sep 17 00:00:00 2001 From: Federico Fiaschi Date: Sun, 4 Aug 2024 20:51:14 +0200 Subject: [PATCH 2/6] test: add test for exponential search --- search/test/exponential_search.test.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 search/test/exponential_search.test.ts diff --git a/search/test/exponential_search.test.ts b/search/test/exponential_search.test.ts new file mode 100644 index 00000000..8eaa5d75 --- /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); + } + ); +}); From 44b698d3f9783b20294b60b825960bc71b5a31fe Mon Sep 17 00:00:00 2001 From: Federico Fiaschi Date: Sun, 4 Aug 2024 22:02:36 +0200 Subject: [PATCH 3/6] fix : prettier fix --- search/exponential_search.ts | 67 +++++++++++++------------- search/test/exponential_search.test.ts | 8 +-- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/search/exponential_search.ts b/search/exponential_search.ts index 01c68051..0b1a2ddf 100644 --- a/search/exponential_search.ts +++ b/search/exponential_search.ts @@ -13,38 +13,37 @@ */ 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; - } - - return binarySearch(array, x, i / 2, Math.min(i, arrayLength - 1)); - }; - - const binarySearch = ( - array: number[], - x: number, - start: number, - end: number - ): number | null => { - while (start <= end) { - const mid = Math.floor((start + end) / 2); - if (array[mid] === x) { - return mid; - } else if (array[mid] < x) { - start = mid + 1; - } else { - end = mid - 1; - } + 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 + } + + return binarySearch(array, x, i / 2, Math.min(i, arrayLength - 1)) +} + +const binarySearch = ( + array: number[], + x: number, + start: number, + end: number +): number | null => { + while (start <= end) { + const mid = Math.floor((start + end) / 2) + if (array[mid] === x) { + return mid + } else if (array[mid] < x) { + start = mid + 1 + } else { + end = mid - 1 } - return null; - }; - \ No newline at end of file + } + return null +} diff --git a/search/test/exponential_search.test.ts b/search/test/exponential_search.test.ts index 8eaa5d75..80f6a07f 100644 --- a/search/test/exponential_search.test.ts +++ b/search/test/exponential_search.test.ts @@ -1,4 +1,4 @@ -import { exponentialSearch } from '../exponential_search'; +import { exponentialSearch } from '../exponential_search' describe('Exponential search', () => { test.each([ @@ -13,7 +13,7 @@ describe('Exponential search', () => { ])( 'of %o, searching for %o, expected %i', (array: number[], target: number, expected: number | null) => { - expect(exponentialSearch(array, target)).toBe(expected); + expect(exponentialSearch(array, target)).toBe(expected) } - ); -}); + ) +}) From 61b1d22d1853b670ebfd1403525c874077d7fc01 Mon Sep 17 00:00:00 2001 From: Federico Fiaschi Date: Sun, 4 Aug 2024 22:58:40 +0200 Subject: [PATCH 4/6] fix: added parameters to iterative binary search --- search/binary_search.ts | 12 ++++++------ search/exponential_search.ts | 30 +++++++++++------------------- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/search/binary_search.ts b/search/binary_search.ts index 39d380a4..2d18dca8 100644 --- a/search/binary_search.ts +++ b/search/binary_search.ts @@ -16,18 +16,18 @@ export const binarySearchIterative = ( array: number[], - target: number + target: number, + start: number = 0, + end: number = array.length - 1 ): 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 - // ensure the target is within the bounds of the array if (target < array[start] || target > array[end]) return -1 + // 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 // otherwise, move the start pointer to be middle + 1 diff --git a/search/exponential_search.ts b/search/exponential_search.ts index 0b1a2ddf..19c3409f 100644 --- a/search/exponential_search.ts +++ b/search/exponential_search.ts @@ -1,9 +1,16 @@ +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. + * Exponential search doubles the search time with each iteration. + * * @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 @@ -26,24 +33,9 @@ export const exponentialSearch = ( i = i * 2 } - return binarySearch(array, x, i / 2, Math.min(i, arrayLength - 1)) -} + const start = Math.floor(i / 2) + const end = Math.min(i, arrayLength - 1) + const result = binarySearchIterative(array, x, start, end) -const binarySearch = ( - array: number[], - x: number, - start: number, - end: number -): number | null => { - while (start <= end) { - const mid = Math.floor((start + end) / 2) - if (array[mid] === x) { - return mid - } else if (array[mid] < x) { - start = mid + 1 - } else { - end = mid - 1 - } - } - return null + return result !== -1 ? result : null } From 6d55e80135a736c9ee32492f570ccebeb8832ae3 Mon Sep 17 00:00:00 2001 From: Federico Fiaschi Date: Sun, 4 Aug 2024 23:02:23 +0200 Subject: [PATCH 5/6] fix: prettier fix #2 --- search/exponential_search.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/search/exponential_search.ts b/search/exponential_search.ts index 19c3409f..2bb34d88 100644 --- a/search/exponential_search.ts +++ b/search/exponential_search.ts @@ -7,8 +7,8 @@ import { binarySearchIterative } from './binary_search' * 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. + * 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. * Exponential search doubles the search time with each iteration. * * @param {number[]} array - sorted list of numbers From 2c6a281b54e4e23f2d1701f15a60114e48c6a7d8 Mon Sep 17 00:00:00 2001 From: Federico Fiaschi Date: Mon, 5 Aug 2024 00:11:17 +0200 Subject: [PATCH 6/6] fix: modified the return on binary search and related tests --- search/binary_search.ts | 20 ++++++++++---------- search/exponential_search.ts | 3 +-- search/test/binary_search.test.ts | 16 +++++++++------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/search/binary_search.ts b/search/binary_search.ts index 2d18dca8..cf86f39a 100644 --- a/search/binary_search.ts +++ b/search/binary_search.ts @@ -8,10 +8,10 @@ * * @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 = ( @@ -19,11 +19,11 @@ export const binarySearchIterative = ( target: number, start: number = 0, end: number = 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 // declare pointers for the middle index let middle = (start + end) >> 1 @@ -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 index 2bb34d88..4a8eba47 100644 --- a/search/exponential_search.ts +++ b/search/exponential_search.ts @@ -9,7 +9,6 @@ import { binarySearchIterative } from './binary_search' * 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. - * Exponential search doubles the search time with each iteration. * * @param {number[]} array - sorted list of numbers * @param {number} x - target number to search for @@ -37,5 +36,5 @@ export const exponentialSearch = ( const end = Math.min(i, arrayLength - 1) const result = binarySearchIterative(array, x, start, end) - return result !== -1 ? result : null + 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)