diff --git a/Sorts/TournamentSort.js b/Sorts/TournamentSort.js new file mode 100644 index 0000000000..f4115863a4 --- /dev/null +++ b/Sorts/TournamentSort.js @@ -0,0 +1,62 @@ +/* + * Tournament Sort + * + * Tournament Sort improves upon naive Selection Sort by using a min-heap + * (priority queue) to find the minimum element in O(log n) instead of O(n), + * giving an overall time complexity of O(n log n). + * + * The name comes from its resemblance to a single-elimination sports tournament + * where the winner (minimum element) is found each round. + * + * Reference: https://en.wikipedia.org/wiki/Tournament_sort + */ + +/** + * Restores the min-heap property by sifting down from index i. + * @param {number[]} heap - The heap array + * @param {number} n - Size of the heap + * @param {number} i - Index to sift down from + */ +const heapify = (heap, n, i) => { + let smallest = i + const left = 2 * i + 1 + const right = 2 * i + 2 + + if (left < n && heap[left] < heap[smallest]) smallest = left + if (right < n && heap[right] < heap[smallest]) smallest = right + + if (smallest !== i) { + ;[heap[i], heap[smallest]] = [heap[smallest], heap[i]] + heapify(heap, n, smallest) + } +} + +/** + * Sorts an array using Tournament Sort. + * @param {number[]} arr - The array to sort + * @returns {number[]} The sorted array + */ +const tournamentSort = (arr) => { + if (arr.length <= 1) return arr + + const heap = [...arr] + const result = [] + + // Build min-heap + for (let i = Math.floor(heap.length / 2) - 1; i >= 0; i--) { + heapify(heap, heap.length, i) + } + + // Extract minimum elements one by one + let size = heap.length + while (size > 0) { + result.push(heap[0]) + heap[0] = heap[size - 1] + size-- + heapify(heap, size, 0) + } + + return result +} + +export { tournamentSort } diff --git a/Sorts/TournamentSort.test.js b/Sorts/TournamentSort.test.js new file mode 100644 index 0000000000..b1ae57306d --- /dev/null +++ b/Sorts/TournamentSort.test.js @@ -0,0 +1,31 @@ +import { tournamentSort } from './TournamentSort.js' + +describe('Tournament Sort', () => { + it('should sort an unsorted array', () => { + expect(tournamentSort([5, 3, 1, 4, 2])).toEqual([1, 2, 3, 4, 5]) + }) + + it('should handle an already sorted array', () => { + expect(tournamentSort([1, 2, 3, 4, 5])).toEqual([1, 2, 3, 4, 5]) + }) + + it('should handle a reverse sorted array', () => { + expect(tournamentSort([5, 4, 3, 2, 1])).toEqual([1, 2, 3, 4, 5]) + }) + + it('should handle a single element array', () => { + expect(tournamentSort([42])).toEqual([42]) + }) + + it('should handle an empty array', () => { + expect(tournamentSort([])).toEqual([]) + }) + + it('should handle duplicates', () => { + expect(tournamentSort([3, 1, 2, 1, 3])).toEqual([1, 1, 2, 3, 3]) + }) + + it('should handle negative numbers', () => { + expect(tournamentSort([-3, 0, -1, 5, 2])).toEqual([-3, -1, 0, 2, 5]) + }) +})