Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exponential search #247

Merged
merged 7 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Fechuli marked this conversation as resolved.
Show resolved Hide resolved
* 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)
}
)
})
Loading