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

feat: add sentinel search algorithm #1683

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions Search/QuickSelectSearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export function quickSelectSearch(array, k) {
while (from < to) {
let left = from
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please keep unrelated changes out of this PR.

let right = to

const pivot = array[Math.ceil((left + right) * 0.5)]

while (left < right) {
Expand Down
35 changes: 35 additions & 0 deletions Search/SentinelSearch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @description Sentinel linear search is a variation of the standard linear search algorithm used to
* find a target value in an array or list. The basic idea behind this algorithm is to add a
* sentinel value at the end of the array which is equal to the target value we are looking for.
* This helps to avoid checking the array boundary condition during each iteration of the loop,
* as the sentinel value acts as a stopper for the loop.
*
* @param {number[]} array - sorted list of numbers
* @param {number} target - target number to search for
* @return {number | null} - index of the target number in the list, or null if not found
* @see [SentinelSearch](https://www.geeksforgeeks.org/sentinel-linear-search/)
* @example sentinelSearch([1,2,3], 2) => 1
* @example sentinelSearch([4,5,6], 2) => null
* @complexity_analysis
* Time Complexity : O(n)
* Auxiliary Space: O(1)
*/

export const sentinelSearch = (array, target) => {
const arrayLength = array.length
if (arrayLength === 0) return null

// Element to be searched is placed at the last index
const last = array[arrayLength - 1]
array[arrayLength - 1] = target

let index = 0
while (array[index] !== target) index++

// Put the last element back
array[arrayLength - 1] = last

if (index < arrayLength - 1 || array[arrayLength - 1] === target) return index
return null
}
69 changes: 30 additions & 39 deletions Search/TernarySearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,38 +12,33 @@
*/

function ternarySearchRecursive(arr, key, low = 0, high = arr.length - 1) {
if (high >= low) {
// find the mid1 and mid2
const mid1 = Math.floor(low + (high - low) / 3)
const mid2 = Math.floor(high - (high - low) / 3)
// if low > high => we have searched the whole array without finding the item
if (low > high) return -1

// check if key is found at any mid
if (arr[mid1] === key) {
// return index of key if found
return mid1
}
if (arr[mid2] === key) {
// return index of key if found
return mid2
}
// find the mid1 and mid2
const mid1 = Math.floor(low + (high - low) / 3)
const mid2 = Math.floor(high - (high - low) / 3)

// since the key is not found at mid,
// check in which region it is present
// and repeat the Search operation
// in that region
if (key < arr[mid1]) {
// the key lies in between low and mid1
return ternarySearchRecursive(arr, key, low, mid1 - 1)
} else if (key > arr[mid2]) {
// the key lies in between mid2 and high
return ternarySearchRecursive(arr, key, mid2 + 1, high)
} else {
// the key lies in between mid1 and mid2
return ternarySearchRecursive(arr, key, mid1 + 1, mid2 - 1)
}
// check if key is found at any mid
// return index of key if found
if (arr[mid1] === key) return mid1

// return index of key if found
if (arr[mid2] === key) return mid2

// since the key is not found at mid,
// check in which region it is present
// and repeat the Search operation
// in that region
if (key < arr[mid1]) {
// the key lies in between low and mid1
return ternarySearchRecursive(arr, key, low, mid1 - 1)
} else if (key > arr[mid2]) {
// the key lies in between mid2 and high
return ternarySearchRecursive(arr, key, mid2 + 1, high)
} else {
// if low > high => we have searched the whole array without finding the item
return -1
// the key lies in between mid1 and mid2
return ternarySearchRecursive(arr, key, mid1 + 1, mid2 - 1)
}
}

Expand All @@ -54,14 +49,11 @@ function ternarySearchIterative(arr, key, low = 0, high = arr.length - 1) {
const mid2 = Math.floor(high - (high - low) / 3)

// check if key is found at any mid
if (arr[mid1] === key) {
// return index of key if found
return mid1
}
if (arr[mid2] === key) {
// return index of key if found
return mid2
}
// return index of key if found
if (arr[mid1] === key) return mid1

// return index of key if found
if (arr[mid2] === key) return mid2

// since the key is not found at mid,
// check in which region it is present
Expand All @@ -75,8 +67,7 @@ function ternarySearchIterative(arr, key, low = 0, high = arr.length - 1) {
low = mid2 + 1
} else {
// the key lies in between mid1 and mid2
low = mid1 + 1
high = mid2 - 1
;[low, high] = [mid1 + 1, mid2 - 1]
}
}
// the key was not found
Expand Down
13 changes: 13 additions & 0 deletions Search/test/SentinelSearch.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { sentinelSearch } from '../SentinelSearch'

describe('Sentinel search', () => {
test.each([
[['o', 'b', 'c'], 'c', 2],
[[1, 2, 3, 4, 5], 4, 3],
[['s', 't', 'r', 'i', 'n', 'g'], 'a', null],
[['1', '2', '3'], '1', 0],
[['4', 'e', '6', '10'], 4, null]
])('of %o , searching for %o, expected %i', (array, target, index) => {
expect(sentinelSearch(array, target)).toStrictEqual(index)
})
})
14 changes: 11 additions & 3 deletions Search/test/TernarySearch.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ test('should return the index of a number in an array of numbers:', () => {
test('should return the index of a string in an array of strings:', () => {
const indexNumber = ternarySearchRecursive(
['Ali', 'Cathrynli', 'Josuke', 'Thomas'],
'Cathrynli'
'Josuke'
)
expect(indexNumber).toBe(1)
expect(indexNumber).toBe(2)
})

test('should return the index of a string in an array of strings:', () => {
const indexNumber = ternarySearchRecursive(
const indexNumber = ternarySearchIterative(
['Ali', 'Cathrynli', 'Josuke', 'Thomas'],
'Josuke'
)
Expand All @@ -49,3 +49,11 @@ test('should return the index of a string in an array of strings:', () => {
)
expect(indexNumber).toBe(-1)
})

test('should return the index of a string in an array of strings:', () => {
const indexNumber = ternarySearchIterative(
['Ali', 'Cathrynli', 'Josuke', 'Thomas'],
'Angela'
)
expect(indexNumber).toBe(-1)
})