源文件地址:https://github.com/ArthasModern/algorjs/blob/master/sort.js
测试Demo地址:https://github.com/ArthasModern/algorjs/blob/master/demo.js
排序算法中三种最为通用的排序算法:
mergeSort ---- 归并排序 ---- 时间复杂度O(nlogn)
heapSort ---- 堆排序 ---- 时间复杂度O(nlogn)
quickSort ---- 快速排序 ---- 时间复杂度O(nlogn) -> O(n^2)
很多算法示例中,都是以最简单的`整数升序排序`为例编写排序算法
但是我们实际需求中,常常要对复杂对象进行升序、降序、甚至自定义优先级序列进行排序
每次都要根据需求\场景重写排序算法是一件痛苦且繁琐的事情,且容易出错
基于代码复用原则,我们考虑如何扩展排序算法,让它变得更通用
扩展为可以自定义比较方法`compFunc`
通过自定义比较方法,可以自由实现对任意数据结构的比较排序;
比如,按年岁`man.age`排序;
比如,正序、倒序、自定义优先级排序等等;
下面是Demo与实现
使用Demo如下:
const Sort = require("./sort");
//**************** 正序
console.log(Sort.mergeSort([6, 8, 4, 3, 2, 7, 5, 1, 9, 0]));
console.log(Sort.heapSort([6, 8, 4, 3, 2, 7, 5, 1, 9, 0]));
console.log(Sort.quickSort([6, 8, 4, 3, 2, 7, 5, 1, 9, 0]));
//**************** 倒序
const reverseCompFunc = (a, b) => {
if (a > b) { return -1; }
else if (a < b) { return 1; }
else { return 0; }
};
console.log(Sort.mergeSort([6, 8, 4, 3, 2, 7, 5, 1, 9, 0], reverseCompFunc));
console.log(Sort.heapSort([6, 8, 4, 3, 2, 7, 5, 1, 9, 0], reverseCompFunc));
console.log(Sort.quickSort([6, 8, 4, 3, 2, 7, 5, 1, 9, 0], reverseCompFunc));
//**************** 自定义比较方法
const oldCompFunc = function(a, b) {
// 按年岁从大到小 ---- 长者优先
if (a.age > b.age) { return -1; }
else if (a.age < b.age) { return 1; }
else { return 0; }
};
const man0 = { age: 3 };
const man1 = { age: 10 };
const man2 = { age: 20 };
const man3 = { age: 32 };
const man4 = { age: 45 };
const man5 = { age: 60 };
console.log(Sort.mergeSort([man3, man0, man5, man2, man1, man4], oldCompFunc));
console.log(Sort.heapSort([man3, man0, man5, man2, man1, man4], oldCompFunc));
console.log(Sort.quickSort([man3, man0, man5, man2, man1, man4], oldCompFunc));
通用排序算法实现如下:
/****************************************************************
* 三种最为通用的排序算法
* 1)归并排序
* 2)堆排序
* 3)快速排序
* 支持自定义比较方法:
* ---- 正序、倒序、自定义优先级、复杂对象按自定义属性比较等等
****************************************************************/
"use strict"
/****************************************************************
* 归并排序
* 复杂度:O(nlogn)
* 说明:非空间原址
*******************************
* @method mergeSort
* @param {Array} arr
* @param {Function} compFunc - compare function
* sample:
* function compFunc(a, b) {
* if (a > b) { return 1; }
* else if (a < b) { return -1 };
* return 0;
* }
* @return sorted Array
****************************************************************/
function mergeSort(arr, compFunc) {
// 补全
let p = 0;
let r = arr.length - 1;
if (compFunc === undefined) {
compFunc = (a, b) => {
if (a > b) { return 1; }
else if (a < b) { return -1; }
else { return 0; }
}
}
// Inner
function mergeSortInner(arr, p, r) {
// 归并
function merge(arr, p, q, r) {
let larr = arr.slice(p, q);
let rarr = arr.slice(q, r + 1);
let llen = larr.length;
let rlen = rarr.length;
for (let i = 0, j = 0, k = p; k <= r; ++k) {
if (j >= rlen ||
(i < llen && compFunc(larr[i], rarr[j]) <= 0)) {
arr[k] = larr[i];
++i;
} else {
arr[k] = rarr[j];
++j;
}
}
}
// 递归
if (p < r) {
let q = parseInt((p + r) / 2) + 1;
mergeSortInner(arr, p, q - 1);
mergeSortInner(arr, q, r);
merge(arr, p, q, r);
}
return arr;
}
return mergeSortInner(arr, p, r);
}
/****************************************************************
* 堆排序
* 复杂度:O(nlogn)
* 说明:是空间原址
*******************************
* @method heapSort
* @param {Array} arr
* @param {Function} compFunc - compare function
* sample:
* function compFunc(a, b) {
* if (a > b) { return 1; }
* else if (a < b) { return -1 };
* return 0;
* }
* @return sorted Array
****************************************************************/
function heapSort(arr, compFunc) {
// 补全
if (compFunc === undefined) {
compFunc = (a, b) => {
if (a > b) { return 1; }
else if (a < b) { return -1; }
else { return 0; }
}
}
// 保序
function keepMaxHeap(arr, i) {
function parentIdx(i) {
return parseInt(i / 2);
}
function leftIdx(i) {
return i * 2;
}
function rightIdx(i) {
return i * 2 + 1;
}
let l = leftIdx(i);
let r = rightIdx(i);
let maxIdx = i;
if (l < arr.heapSize && compFunc(arr[l], arr[maxIdx]) > 0) {
maxIdx = l;
}
if (r < arr.heapSize && compFunc(arr[r], arr[maxIdx]) > 0) {
maxIdx = r;
}
// 交换最大值到父节点
if (maxIdx !== i) {
let temp = arr[i];
arr[i] = arr[maxIdx];
arr[maxIdx] = temp;
// 递归对子节点再做校验
keepMaxHeap(arr, maxIdx);
}
}
// 建堆
function buildHeap(arr) {
arr.heapSize = arr.length;
for (let i = parseInt(arr.heapSize / 2); i >= 0; --i) {
keepMaxHeap(arr, i);
}
}
buildHeap(arr);
for (let i = arr.length - 1; i >= 0; --i) {
let temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
// 循环保序
--arr.heapSize;
keepMaxHeap(arr, 0);
}
// 清理辅助属性
delete arr.heapSize;
return arr;
}
/****************************************************************
* 快速排序
* 期望复杂度:O(nlogn)
* 最坏复杂度:O(n^2)
* 说明:是空间原址
*******************************
* @method quickSort
* @param {Array} arr
* @param {Function} compFunc - compare function
* sample:
* function compFunc(a, b) {
* if (a > b) { return 1; }
* else if (a < b) { return -1 };
* return 0;
* }
* @return sorted Array
****************************************************************/
function quickSort(arr, compFunc) {
// 补全
let p = 0;
let r = arr.length - 1;
if (compFunc === undefined) {
compFunc = (a, b) => {
if (a > b) { return 1; }
else if (a < b) { return -1; }
else { return 0; }
}
}
// Inner
function quickSortInner(arr, p, r) {
// 按与arr[r]比较进行分列
function partition(arr, p, r) {
let i = p - 1;
for (let j = p; j < r; ++j) {
// 将小于arr[r]的元素交换到i后面的位置
if (compFunc(arr[j], arr[r]) < 0) {
++i;
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
// 将arr[r]元素交换到i后的位置
++i;
let temp = arr[r];
arr[r] = arr[i];
arr[i] = temp;
return i;
}
if (p < r) {
// 分列
let q = partition(arr, p, r);
// 再分别对左右两组元素递归快排
quickSortInner(arr, p, q - 1);
quickSortInner(arr, q + 1, r);
}
return arr;
}
return quickSortInner(arr, p, r);
}
/****************************************************************/
exports.mergeSort = mergeSort;
exports.heapSort = heapSort;
exports.quickSort = quickSort;