JS模拟排序算法和搜索算法
Typescript版本的排序和搜索算法
排序算法
算法中用到的公共函数
const Compare = { LESS_THAN: -1, BIGGER_THAN: 1, EQUALS: 0 }; const DOES_NOT_EXIST = -1; function lesserEquals(a, b, compareFn) { const comp = compareFn(a, b); return comp === Compare.LESS_THAN || comp === Compare.EQUALS; } function biggerEquals(a, b, compareFn) { const comp = compareFn(a, b); return comp === Compare.BIGGER_THAN || comp === Compare.EQUALS; } function defaultCompare(a, b) { if (a === b) { return Compare.EQUALS; } return a < b ? Compare.LESS_THAN : Compare.BIGGER_THAN; } function defaultEquals(a, b) { return a === b; } function defaultToString(item) { if (item === null) { return 'NULL'; } else if (item === undefined) { return 'UNDEFINED'; } else if (typeof item === 'string' || item instanceof String) { return `${item}`; } return item.toString(); } function swap(array, a, b) { [array[a], array[b]] = [array[b], array[a]]; } function reverseCompare(compareFn) { return (a, b) => compareFn(b, a); } function defaultDiff(a, b) { return Number(a) - Number(b); }
冒泡排序
function bubbleSort(array, compareFn = defaultCompare) { const { length } = array; for (let i = 0; i < length; i++) { // console.log('--- '); for (let j = 0; j < length - 1; j++) { // console.log('compare ' + array[j] + ' with ' + array[j + 1]); if (compareFn(array[j], array[j + 1]) === Compare.BIGGER_THAN) { // console.log('swap ' + array[j] + ' with ' + array[j + 1]); swap(array, j, j + 1); } } } return array; }
改进的冒泡排序(减少中间比较)
function modifiedBubbleSort(array, compareFn = defaultCompare) { const { length } = array; for (let i = 0; i < length; i++) { // console.log('--- '); for (let j = 0; j < length - 1 - i; j++) { // console.log('compare ' + array[j] + ' with ' + array[j + 1]); if (compareFn(array[j], array[j + 1]) === Compare.BIGGER_THAN) { // console.log('swap ' + array[j] + ' with ' + array[j + 1]); swap(array, j, j + 1); } } } return array; }
选择排序
function selectionSort (array, compareFn = defaultCompare) => { const { length } = array; let indexMin; for (let i = 0; i < length - 1; i++) { indexMin = i; // console.log('index ' + array[i]); for (let j = i; j < length; j++) { if (compareFn(array[indexMin], array[j]) === Compare.BIGGER_THAN) { // console.log('new index min ' + array[j]); indexMin = j; } } if (i !== indexMin) { // console.log('swap ' + array[i] + ' with ' + array[indexMin]); swap(array, i, indexMin); } } return array; };
插入排序
function insertionSort (array, compareFn = defaultCompare) => { const { length } = array; let temp; for (let i = 1; i < length; i++) { let j = i; temp = array[i]; // console.log('to be inserted ' + temp); while (j > 0 && compareFn(array[j - 1], temp) === Compare.BIGGER_THAN) { // console.log('shift ' + array[j - 1]); array[j] = array[j - 1]; j--; } // console.log('insert ' + temp); array[j] = temp; } return array; };
归并排序
function merge(left, right, compareFn) { let i = 0; let j = 0; const result = []; while (i < left.length && j < right.length) { result.push(compareFn(left[i], right[j]) === Compare.LESS_THAN ? left[i++] : right[j++]); } return result.concat(i < left.length ? left.slice(i) : right.slice(j)); } function mergeSort(array, compareFn = defaultCompare) { if (array.length > 1) { const { length } = array; const middle = Math.floor(length / 2); const left = mergeSort(array.slice(0, middle), compareFn); const right = mergeSort(array.slice(middle, length), compareFn); array = merge(left, right, compareFn); } return array; }
快速排序
// 划分过程 function partition(array, left, right, compareFn) { const pivot = array[Math.floor((right + left) / 2)]; let i = left; let j = right; while (i <= j) { while (compareFn(array[i], pivot) === Compare.LESS_THAN) { i++; } while (compareFn(array[j], pivot) === Compare.BIGGER_THAN) { j--; } if (i <= j) { swap(array, i, j); i++; j--; } } return i; } function quick(array, left, right, compareFn) { let index; if (array.length > 1) { index = partition(array, left, right, compareFn); if (left < index - 1) { quick(array, left, index - 1, compareFn); } if (index < right) { quick(array, index, right, compareFn); } } return array; } function quickSort(array, compareFn = defaultCompare) { return quick(array, 0, array.length - 1, compareFn); }
计数排序
function countingSort(array) { if (array.length < 2) { return array; } const maxValue = findMaxValue(array); let sortedIndex = 0; const counts = new Array(maxValue + 1); array.forEach(element => { if (!counts[element]) { counts[element] = 0; } counts[element]++; }); // console.log('Frequencies: ' + counts.join()); counts.forEach((element, i) => { while (element > 0) { array[sortedIndex++] = i; element--; } }); return array; }
桶排序
// 引入前面的插入排序 import { insertionSort } from './insertion-sort'; function createBuckets(array, bucketSize) { let minValue = array[0]; let maxValue = array[0]; for (let i = 1; i < array.length; i++) { if (array[i] < minValue) { minValue = array[i]; } else if (array[i] > maxValue) { maxValue = array[i]; } } const bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1; const buckets = []; for (let i = 0; i < bucketCount; i++) { buckets[i] = []; } for (let i = 0; i < array.length; i++) { buckets[Math.floor((array[i] - minValue) / bucketSize)].push(array[i]); } return buckets; } function sortBuckets(buckets) { const sortedArray = []; for (let i = 0; i < buckets.length; i++) { if (buckets[i] != null) { insertionSort(buckets[i]); sortedArray.push(...buckets[i]); } } return sortedArray; } function bucketSort(array, bucketSize = 5) { if (array.length < 2) { return array; } const buckets = createBuckets(array, bucketSize); return sortBuckets(buckets); }
基数排序
function findMaxValue(array, compareFn = defaultCompare) { if (array && array.length > 0) { let max = array[0]; for (let i = 1; i < array.length; i++) { if (compareFn(max, array[i]) === Compare.LESS_THAN) { max = array[i]; } } return max; } return undefined; } function findMinValue(array, compareFn = defaultCompare) { if (array && array.length > 0) { let min = array[0]; for (let i = 1; i < array.length; i++) { if (compareFn(min, array[i]) === Compare.BIGGER_THAN) { min = array[i]; } } return min; } return undefined; } const getBucketIndex = (value, minValue, significantDigit, radixBase) => Math.floor(((value - minValue) / significantDigit) % radixBase); const countingSortForRadix = (array, radixBase, significantDigit, minValue) => { let bucketsIndex; const buckets = []; const aux = []; for (let i = 0; i < radixBase; i++) { buckets[i] = 0; } for (let i = 0; i < array.length; i++) { bucketsIndex = getBucketIndex(array[i], minValue, significantDigit, radixBase); buckets[bucketsIndex]++; } for (let i = 1; i < radixBase; i++) { buckets[i] += buckets[i - 1]; } for (let i = array.length - 1; i >= 0; i--) { bucketsIndex = getBucketIndex(array[i], minValue, significantDigit, radixBase); aux[--buckets[bucketsIndex]] = array[i]; } for (let i = 0; i < array.length; i++) { array[i] = aux[i]; } return array; }; function radixSort(array, radixBase = 10) { if (array.length < 2) { return array; } const minValue = findMinValue(array); const maxValue = findMaxValue(array); // Perform counting sort for each significant digit, starting at 1 let significantDigit = 1; while ((maxValue - minValue) / significantDigit >= 1) { array = countingSortForRadix(array, radixBase, significantDigit, minValue); significantDigit *= radixBase; } return array; }
搜索算法
顺序搜索
function sequentialSearch(array, value, equalsFn = defaultEquals) { for (let i = 0; i < array.length; i++) { if (equalsFn(value, array[i])) { return i; } } return DOES_NOT_EXIST; }
二分搜索
// 引入文章前面的快速排序方法 import { quickSort } from 'quicksort'; function binarySearch(array, value, compareFn = defaultCompare) { const sortedArray = quickSort(array); let low = 0; let high = sortedArray.length - 1; while (low <= high) { const mid = Math.floor((low + high) / 2); const element = sortedArray[mid]; // console.log('mid element is ' + element); if (compareFn(element, value) === Compare.LESS_THAN) { low = mid + 1; // console.log('low is ' + low); } else if (compareFn(element, value) === Compare.BIGGER_THAN) { high = mid - 1; // console.log('high is ' + high); } else { // console.log('found it'); return mid; } } return DOES_NOT_EXIST; }
内插搜索
// 引入前面的工具函数和相关变量 import { biggerEquals, Compare, defaultCompare, defaultEquals, defaultDiff, DOES_NOT_EXIST, lesserEquals } from '../../util'; function interpolationSearch( array, value, compareFn = defaultCompare, equalsFn = defaultEquals, diffFn = defaultDiff ) { const { length } = array; let low = 0; let high = length - 1; let position = -1; let delta = -1; while ( low <= high && biggerEquals(value, array[low], compareFn) && lesserEquals(value, array[high], compareFn) ) { delta = diffFn(value, array[low]) / diffFn(array[high], array[low]); position = low + Math.floor((high - low) * delta); if (equalsFn(array[position], value)) { return position; } if (compareFn(array[position], value) === Compare.LESS_THAN) { low = position + 1; } else { high = position - 1; } } return DOES_NOT_EXIST; }
随机算法Fisher—Yates(洗扑克牌)
function shuffle(array) { for(let i=array.length;i>0;i--) { const randomIndex = Math.floor(Math.random()*(i+1)); swap(array, i, randomIndex); } return array; }
相关推荐
randy0 2020-11-17
lixiaotao 2020-10-07
美丽的泡沫 2020-09-08
nongfusanquan0 2020-08-18
hang0 2020-08-16
earthhouge 2020-08-15
算法改变人生 2020-07-28
troysps 2020-07-19
Broadview 2020-07-19
chenfei0 2020-07-18
风吹夏天 2020-07-07
yangjingdong00 2020-07-05
数据与算法之美 2020-07-05
shawsun 2020-07-04
数据与算法之美 2020-07-04
要知道时间复杂度只是描述一个增长趋势,复杂度为O的排序算法执行时间不一定比复杂度为O长,因为在计算O时省略了系数、常数、低阶。实际上,在对小规模数据进行排序时,n2的值实际比 knlogn+c还要小。
Evankaka 2020-07-04
田有朋 2020-06-28