稳定排序
稳定排序是指,如果原数组中有多个元素是“相等的”,那么这些元素在排序后数组的相对顺序应该保持不变。
比如:我们对{name:string, age:number}[]
数组用age进行排序,有很多人是25岁,那么在排序后的数组中,这些25岁的人应该按照它们【在原数组中出现的顺序】来排列。
原生的sort是不一定是稳定的,因为不同的引擎实现不同,比如V8的sort就用到快排,快排不是稳定的排序。
为什么需要稳定的排序?其中一种情况是:原列表已经在某个字段上排好序,然而要排序的字段上可能有很多项是“相等”的。
比如有一个{name:string, age:number}[]
数组,它【已经在name上按照字母顺序排好序】了,现在希望按照age来排序。假设有很多人的age是25,如果排序是稳定的话,就能保证这些25岁的人【在输出列表中是按照字母顺序排列的】,这样的话输出的列表会好看很多。
实现
typescript
/**
* @description 归并排序(稳定排序)。
* 此方法会改变原数组,如果不想破坏原数组,调用者自己创建数组副本作为参数。
*/
function mergeSort<T>(arr: T[], compare: (a: T, b: T) => -1 | 0 | 1): T[] {
if (!Array.isArray(arr)) {
throw new Error('mergeSort的参数必须为数组');
}
_ms(arr, compare, 0, arr.length);
return arr;
}
/**
* @description 排序范围:[begin, end)
*/
function _ms<T>(arr: T[], compare: (a: T, b: T) => -1 | 0 | 1, begin: number, end: number): void {
const size = end - begin;
if (size <= 1) { return; }
// tslint:disable-next-line: no-bitwise
const middle = (end + begin) >> 1;
_ms(arr, compare, begin, middle);
_ms(arr, compare, middle, end);
if (compare(arr[middle - 1], arr[middle]) <= 0) { return; } // 顺序已经正确
const merged = [];
let leftIndex = begin, rightIndex = middle;
while (merged.length < size) {
if (leftIndex === middle) {
merged.push(arr[rightIndex++]);
} else if (rightIndex === end) {
merged.push(arr[leftIndex++]);
} else {
const c = compare(arr[leftIndex], arr[rightIndex]);
if (c <= 0) {
merged.push(arr[leftIndex++]);
} else {
merged.push(arr[rightIndex++]);
}
}
}
arr.splice(begin, size, ...merged);
}
JavaScript
/**
* @description 归并排序(稳定排序)。
* 此方法会改变原数组,如果不想破坏原数组,调用者自己创建数组副本作为参数。
*/
function mergeSort(arr, compare) {
if (!Array.isArray(arr)) {
throw new Error('mergeSort的参数必须为数组');
}
_ms(arr, compare, 0, arr.length);
return arr;
}
/**
* @description 排序范围:[begin, end)
*/
function _ms(arr, compare, begin, end) {
var size = end - begin;
if (size <= 1) {
return;
}
// tslint:disable-next-line: no-bitwise
var middle = (end + begin) >> 1;
_ms(arr, compare, begin, middle);
_ms(arr, compare, middle, end);
if (compare(arr[middle - 1], arr[middle]) <= 0) { return; } // 顺序已经正确
var merged = [];
var leftIndex = begin, rightIndex = middle;
while (merged.length < size) {
if (leftIndex === middle) {
merged.push(arr[rightIndex++]);
}
else if (rightIndex === end) {
merged.push(arr[leftIndex++]);
}
else {
var c = compare(arr[leftIndex], arr[rightIndex]);
if (c <= 0) {
merged.push(arr[leftIndex++]);
}
else {
merged.push(arr[rightIndex++]);
}
}
}
arr.splice(begin, size, ...merged);
}
测试
去leetcode上找一道能用排序的题测试,比如75. Sort Colors(虽然说这道题不用排序效率更高)。