Skip to content
Open
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
62 changes: 62 additions & 0 deletions search/ternary_search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* @function ternarySearch
* @description Ternary search is a divide-and-conquer search algorithm similar to binary search.
* It divides the search space into three parts instead of two. It's useful for searching in sorted arrays,
* especially for searching peaks in mountains or similar structures. It can also be used as an alternative to binary search.
* @Complexity_Analysis
* Space complexity - O(log₃ n) (recursion depth)
* Time complexity
* Best case - O(1)
* When the element is at one of the dividing points
* Worst case - O(log₃ n)
* When we need to go through the entire search tree
* Average case - O(log₃ n)
*
* @param {number[]} arr - The sorted input array
* @param {number} target - The target value to search
* @return {number} - The index of the target if found, otherwise -1
* @see [Ternary Search](https://en.wikipedia.org/wiki/Ternary_search)
* @example ternarySearch([1, 2, 3, 4, 5, 6, 7, 8, 9], 5) = 4
*/

export function ternarySearch(arr: number[], target: number): number {
return ternarySearchHelper(arr, target, 0, arr.length - 1);
}

function ternarySearchHelper(
arr: number[],
target: number,
left: number,
right: number,
): number {
if (left > right) {
return -1;
}

// Divide the array into 3 parts
const mid1 = Math.floor(left + (right - left) / 3);
const mid2 = Math.floor(right - (right - left) / 3);

// Check if target is at mid1
if (arr[mid1] === target) {
return mid1;
}

// Check if target is at mid2
if (arr[mid2] === target) {
return mid2;
}

// If target is less than mid1, search in left third
if (target < arr[mid1]) {
return ternarySearchHelper(arr, target, left, mid1 - 1);
}

// If target is greater than mid2, search in right third
if (target > arr[mid2]) {
return ternarySearchHelper(arr, target, mid2 + 1, right);
}

// If target is between mid1 and mid2, search in middle third
return ternarySearchHelper(arr, target, mid1 + 1, mid2 - 1);
}
36 changes: 36 additions & 0 deletions search/test/ternary_search.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { ternarySearch } from '../ternary_search';

describe('Ternary Search', () => {
test('should find the target element', () => {
expect(ternarySearch([1, 2, 3, 4, 5, 6, 7, 8, 9], 5)).toBe(4);
});

test('should return -1 when target is not found', () => {
expect(ternarySearch([1, 2, 3, 4, 5, 6, 7, 8, 9], 10)).toBe(-1);
});

test('should find the first element', () => {
expect(ternarySearch([1, 2, 3, 4, 5], 1)).toBe(0);
});

test('should find the last element', () => {
expect(ternarySearch([1, 2, 3, 4, 5], 5)).toBe(4);
});

test('should handle single element array', () => {
expect(ternarySearch([5], 5)).toBe(0);
});

test('should return -1 for single element array when target not found', () => {
expect(ternarySearch([5], 3)).toBe(-1);
});

test('should handle empty array', () => {
expect(ternarySearch([], 5)).toBe(-1);
});

test('should find element in array with duplicates', () => {
const result = ternarySearch([1, 2, 2, 2, 3, 4, 5], 2);
expect([1, 2, 3]).toContain(result);
});
});
63 changes: 63 additions & 0 deletions sorts/radix_sort.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* @function radixSort
* @description Radix sort is a non-comparative integer sorting algorithm that sorts numbers by processing digits.
* It works by sorting elements digit by digit, starting from the least significant digit to the most significant digit.
* This algorithm is efficient for sorting large numbers of integers with a fixed number of digits.
* @Complexity_Analysis
* Space complexity - O(n + k) where k is the range of input
* Time complexity
* Best case - O(n * d)
* where d is the number of digits
* Worst case - O(n * d)
* where d is the number of digits
* Average case - O(n * d)
* where d is the number of digits
*
* @param {number[]} arr - The input array
* @return {number[]} - The sorted array
* @see [Radix Sort](https://en.wikipedia.org/wiki/Radix_sort)
* @example radixSort([170, 45, 75, 90, 2, 802, 24, 2, 66]) = [2, 2, 24, 45, 66, 75, 90, 170, 802]
*/

export function radixSort(arr: number[]): number[] {
if (arr.length === 0) return arr;

const max = Math.max(...arr);
let exp = 1;

while (max / exp > 0) {
countingSortByDigit(arr, exp);
exp *= 10;
}

return arr;
}

function countingSortByDigit(arr: number[], exp: number): void {
const n = arr.length;
const output: number[] = new Array(n);
const count: number[] = new Array(10).fill(0);

// Count occurrences of each digit
for (let i = 0; i < n; i++) {
const digit = Math.floor((arr[i] / exp) % 10);
count[digit]++;
}

// Change count[i] so that count[i] contains actual position
for (let i = 1; i < 10; i++) {
count[i] += count[i - 1];
}

// Build the output array
for (let i = n - 1; i >= 0; i--) {
const digit = Math.floor((arr[i] / exp) % 10);
output[count[digit] - 1] = arr[i];
count[digit]--;
}

// Copy the output array to arr
for (let i = 0; i < n; i++) {
arr[i] = output[i];
}
}
29 changes: 29 additions & 0 deletions sorts/test/radix_sort.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { radixSort } from '../radix_sort';

describe('Radix Sort', () => {
test('should sort an unsorted array', () => {
expect(radixSort([170, 45, 75, 90, 2, 802, 24, 2, 66])).toEqual([
2, 2, 24, 45, 66, 75, 90, 170, 802,
]);
});

test('should sort a single element array', () => {
expect(radixSort([5])).toEqual([5]);
});

test('should sort an already sorted array', () => {
expect(radixSort([1, 2, 3, 4, 5])).toEqual([1, 2, 3, 4, 5]);
});

test('should sort a reverse sorted array', () => {
expect(radixSort([5, 4, 3, 2, 1])).toEqual([1, 2, 3, 4, 5]);
});

test('should handle empty array', () => {
expect(radixSort([])).toEqual([]);
});

test('should sort array with duplicate elements', () => {
expect(radixSort([3, 3, 1, 1, 2])).toEqual([1, 1, 2, 3, 3]);
});
});