1 import { randomInt } from 'node:crypto'
3 import { bench, group, run } from 'tatami-ng'
6 * @param numberOfWorkers
7 * @param maxNumberOfTasksPerWorker
10 function generateRandomTasksMap (
12 maxNumberOfTasksPerWorker = 10
15 for (let i = 0; i < numberOfWorkers; i++) {
16 const task = [i, randomInt(maxNumberOfTasksPerWorker)]
19 return new Map(tasksArray)
22 const tasksMap = generateRandomTasksMap(60, 20)
28 function loopSelect (tasksMap) {
30 let minValue = Number.POSITIVE_INFINITY
31 for (const [key, value] of tasksMap) {
34 } else if (value < minValue) {
39 return [minKey, minValue]
46 function arraySortSelect (tasksMap) {
47 const tasksArray = Array.from(tasksMap)
48 return tasksArray.sort((a, b) => {
51 } else if (a[1] > b[1]) {
58 const defaultComparator = (a, b) => {
62 const defaultPivotIndexSelect = (leftIndex, rightIndex) => {
63 return leftIndex + Math.floor((rightIndex - leftIndex) / 2)
66 const randomPivotIndexSelect = (leftIndex, rightIndex) => {
67 return randomInt(leftIndex, rightIndex)
75 function swap (array, index1, index2) {
76 const tmp = array[index1]
77 array[index1] = array[index2]
94 compare = defaultComparator
96 const pivotValue = array[pivotIndex]
97 swap(array, pivotIndex, rightIndex)
98 let storeIndex = leftIndex
99 for (let i = leftIndex; i < rightIndex; i++) {
100 if (compare(array[i], pivotValue)) {
101 swap(array, storeIndex, i)
105 swap(array, rightIndex, storeIndex)
115 * @param pivotIndexSelect
118 function selectLoop (
123 compare = defaultComparator,
124 pivotIndexSelect = defaultPivotIndexSelect
127 if (leftIndex === rightIndex) return array[leftIndex]
128 let pivotIndex = pivotIndexSelect(leftIndex, rightIndex)
129 pivotIndex = partition(array, leftIndex, rightIndex, pivotIndex, compare)
130 if (k === pivotIndex) {
132 } else if (k < pivotIndex) {
133 rightIndex = pivotIndex - 1
135 leftIndex = pivotIndex + 1
146 * @param pivotIndexSelect
149 function selectRecursion (
154 compare = defaultComparator,
155 pivotIndexSelect = defaultPivotIndexSelect
157 if (leftIndex === rightIndex) return array[leftIndex]
158 let pivotIndex = pivotIndexSelect(leftIndex, rightIndex)
159 pivotIndex = partition(array, leftIndex, rightIndex, pivotIndex, compare)
160 if (k === pivotIndex) {
162 } else if (k < pivotIndex) {
163 return selectRecursion(array, k, leftIndex, pivotIndex - 1, compare)
165 return selectRecursion(array, k, pivotIndex + 1, rightIndex, k, compare)
173 function quickSelectLoop (tasksMap) {
174 const tasksArray = Array.from(tasksMap)
176 return selectLoop(tasksArray, 0, 0, tasksArray.length - 1, (a, b) => {
185 function quickSelectLoopRandomPivot (tasksMap) {
186 const tasksArray = Array.from(tasksMap)
192 tasksArray.length - 1,
196 randomPivotIndexSelect
204 function quickSelectRecursion (tasksMap) {
205 const tasksArray = Array.from(tasksMap)
207 return selectRecursion(tasksArray, 0, 0, tasksArray.length - 1, (a, b) => {
216 function quickSelectRecursionRandomPivot (tasksMap) {
217 const tasksArray = Array.from(tasksMap)
219 return selectRecursion(
223 tasksArray.length - 1,
227 randomPivotIndexSelect
231 group('Quick select', () => {
232 bench('Loop select', () => {
235 bench('Array sort select', () => {
236 arraySortSelect(tasksMap)
238 bench('Quick select loop', () => {
239 quickSelectLoop(tasksMap)
241 bench('Quick select loop with random pivot', () => {
242 quickSelectLoopRandomPivot(tasksMap)
244 bench('Quick select recursion', () => {
245 quickSelectRecursion(tasksMap)
247 bench('Quick select recursion with random pivot', () => {
248 quickSelectRecursionRandomPivot(tasksMap)