From 4688249c703366f2914c06c490608079709380db Mon Sep 17 00:00:00 2001 From: Lakhan Nad Date: Mon, 17 Aug 2020 14:25:25 +0530 Subject: [PATCH 1/2] Feature: Added IntroSort in JS Closes #265 --- Sorts/IntroSort.js | 307 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 Sorts/IntroSort.js diff --git a/Sorts/IntroSort.js b/Sorts/IntroSort.js new file mode 100644 index 0000000000..e7ba322c5e --- /dev/null +++ b/Sorts/IntroSort.js @@ -0,0 +1,307 @@ +/** + * @function Intosort (As implemented in STD C++ Lib) + * The function performs introsort which is used in + * C++ Standard LIbrary, the implemntation is inspired from] + * library routine itself. + * ALGORITHM: + * 1) It performs quicksort on array until the recursion depth + * exceeds a pre determined limit. + * 2) If the limit is reached it switches to heapsort + * 3) For array size less than a threshold(16) directly + * does insertion sort on array + * @param {Array} array the array to be sorted + * @param {Function} compare the comparison function + * + * @see [Introsort](https://en.wikipedia.org/wiki/Introsort) + * @author [Lakhan Nad](https://github.com/Lakhan-Nad) + */ +function introsort (array, compare) { + /** + * @function Default Comparison Function + * This function is same as implemented by + * Array.sort method + * @see [StackOverflow](https://stackoverflow.com/questions/47334234/how-to-implement-array-prototype-sort-default-compare-function) + * @param {*} a variable 1 + * @param {*} b variable 2 + * @returns {Number} + * -1 if a is less than b + * 0 if a is equal to b + * 1 if a greater than b + */ + var defaultComparator = function (x, y) { + if (x === undefined && y === undefined) return 0 + if (x === undefined) return 1 + if (y === undefined) return -1 + var xString = toString(x) + var yString = toString(y) + if (xString < yString) return -1 + if (xString > yString) return 1 + return 0 + } + /** + * @function helper function for defaultComparator + * Converts a given object to String + * @throws TypeError() + * @param {Object} obj + * @returns {String} String representation of given object + */ + var toString = function (obj) { + if (obj === null) return 'null' + if (typeof obj === 'boolean' || typeof obj === 'number') { + return obj.toString() + } + if (typeof obj === 'string') return obj + if (typeof obj === 'symbol') throw new TypeError() + return obj.toString() + } + /** + * Checks if the value passed is an array + * or not + */ + if (Array.isArray(array) === false) { + return + } + /** + * If the compare parameter is not a function + * or not passed at all use default comparator + * function + */ + if (typeof compare !== 'function') { + compare = defaultComparator // If compare is not a comparator function + } + /** + * Use a closure to define the whole sort + * implementation this is done through + * [IIFE](https://en.wikipedia.org/wiki/Immediately_invoked_function_expression) + */ + return (function (array, comparator) { + var swap = function (index1, index2) { + var temp = array[index1] + array[index1] = array[index2] + array[index2] = temp + } + /** + * @constant THRESHOLD + * If the length of array is less than + * this then we simply perform insertion sort + */ + var THRESHOLD = 16 + /** + * @constant TUNEMAXDEPTH + * Constant usec to increase or decrease value + * of maxDepth + */ + var TUNEMAXDEPTH = 1 + var len = array.length + /** + * Return if array is only of length 1 + * Array of size 1 is always sorted + */ + if (len === 1) { + return + } + /** + * Calculate maxDepth = log2(len) + * Taken from implementation in stdc++ + */ + var maxDepth = Math.floor(Math.log2(len)) * TUNEMAXDEPTH + /** + * The very first call to quicksort + * this initiates sort routine + */ + quickSort(0, len, maxDepth) + /** + * A final checlk call to insertion sort + * on sorted array + */ + insertionSort(0, len) + /** ********************* Implementation of various routines **************************/ + /** + * @function + * This is recursive quicksort implementation in array + * of segment [start,last-1] + * [QuickSort](https://en.wikipedia.org/wiki/Quicksort) + * @param {Number} start the start index of array segment to be sorted + * @param {Number} last one more than the last index of array segment + * @param {Number} depth this measures how many recursive calls are done + */ + function quickSort (start, last, depth) { + if (last - start <= THRESHOLD) { + insertionSort(start, last) + return + } else if (depth <= 0) { + heapSort(start, last) + return + } + var pivot = (last + start) >> 1 + pivot = partition(start, last, pivot) + quickSort(start, pivot, depth - 1) + quickSort(pivot + 1, last, depth - 1) + } + /** + * @function Helper function to quicksort + * @param {Number} start the start of array segment to partitiion + * @param {Number} last one more than last index of the array segment + * @param {Number} pivot the index of pivot to be used + * @returns {Number} the index of pivot after partition + */ + function partition (start, last, pivot) { + swap(start, pivot) + pivot = start + var lo = start + var hi = last + while (true) { + lo++ + while (comparator(array[lo], array[pivot]) <= 0 && lo !== last) { + lo++ + } + hi-- + while (comparator(array[hi], array[pivot]) > 0 && hi !== start) { + hi-- + } + if (lo >= hi) { + break + } + swap(lo, hi) + } + swap(start, hi) + return hi + } + /** + * @function + * Performs insertion sort on array of range + * [start, last-1] + * @param {Number} start the first index of array segment to be sorted + * @param {Number} last one more than last index of array to be sorted + */ + function insertionSort (start, last) { + var i, j + for (i = start + 1; i < last; i++) { + j = i - 1 + while (j >= 0 && comparator(array[j], array[j + 1]) > 0) { + swap(j, j + 1) + j-- + } + } + } + /** + * @function + * Performs heapsort in array segment of range [start, last-1] + * [HeapSort](https://en.wikipedia.org/wiki/Heapsort) + * @param {Number} start the first index of array segment to be sorted + * @param {Number} last one more than last index of array to be sorted + */ + function heapSort (start, last) { + var x = (last + start) >> 1 + while (x - start >= 0) { + heapify(x, start, last) + x-- + } + x = last - 1 + while (x - start > 0) { + swap(start, x) + heapify(start, start, x) + x-- + } + } + /** + * @function Helper function to heapsort routine + * @param {Number} cur the index we need to heapify + * @param {Number} start the start index of array segment that cur belongs to + * @param {Number} last one more than last index of segment that cur belongs to + */ + function heapify (cur, start, last) { + var size = last - start + var max, lt, rt + cur = cur - start + while (true) { + max = cur + lt = 2 * max + 1 + rt = 2 * max + 2 + if ( + lt < size && + comparator(array[start + max], array[start + lt]) < 0 + ) { + max = lt + } + if ( + rt < size && + comparator(array[start + max], array[start + rt]) < 0 + ) { + max = rt + } + if (max !== cur) { + swap(start + cur, start + max) + cur = max + } else { + break + } + } + } + })(array, compare) +} + +/** + * @example Demo run of the sort routine + * The data is randomly generated + * Prints RIGHT:) if the sort routine worked as expected + * If not prints WRONG!! + */ +(function demo () { + const data = [] + const size = 1000000 + var i = 0 + var temp + var c = function (a, b) { + return a - b + } + for (i = 0; i < size; i++) { + temp = Math.random() * Number.MAX_SAFE_INTEGER + data.push(temp) + } + introsort(data, c) + var faulty = false + for (i = 1; i < size; i++) { + if (data[i] < data[i - 1]) { + faulty = true + break + } + } + if (faulty) { + console.log('WRONG!!') + } else { + console.log('RIGHT:)') + } +})(); + +/** + * @example Demo run of the sort routine + * using the default compare function and + * comparing the results with Array.sort + */ +(function demo () { + const data = [] + const data2 = [] + const size = 1000000 + var i = 0 + var temp + for (i = 0; i < size; i++) { + temp = Math.random() * Number.MAX_SAFE_INTEGER + data.push(temp) + data2.push(temp) + } + introsort(data) + data2.sort() + var faulty = false + for (i = 1; i < size; i++) { + if (data[i] !== data2[i]) { + faulty = true + break + } + } + if (faulty) { + console.log('WRONG Implented Comparator!!') + } else { + console.log('Comparator Works Fine:)') + } +})() From 5ca8e011e0163ebcf5e1587eb9963af247bca290 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Mon, 17 Aug 2020 08:56:11 +0000 Subject: [PATCH 2/2] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index f543308684..34153d1cc3 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -102,6 +102,7 @@ * [HeapSort](https://github.com/TheAlgorithms/Javascript/blob/master/Sorts/HeapSort.js) * [HeapSortV2](https://github.com/TheAlgorithms/Javascript/blob/master/Sorts/HeapSortV2.js) * [InsertionSort](https://github.com/TheAlgorithms/Javascript/blob/master/Sorts/InsertionSort.js) + * [IntroSort](https://github.com/TheAlgorithms/Javascript/blob/master/Sorts/IntroSort.js) * [MergeSort](https://github.com/TheAlgorithms/Javascript/blob/master/Sorts/MergeSort.js) * [QuickSort](https://github.com/TheAlgorithms/Javascript/blob/master/Sorts/QuickSort.js) * [RadixSort](https://github.com/TheAlgorithms/Javascript/blob/master/Sorts/RadixSort.js) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy