希尔排序
希尔排序的基本思想是:把序列按一定增量分组,然后对每个分组使用插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
- 希尔排序是插入排序的改进版本。
- 插入排序的问题在于当数组长度扩大时,后面的元素插入时要检查前面n个元素,非常影响排序性能。
function shellSort(arr) {
let length = arr.length;
let interval = Math.floor(length / 2);
//需要循环次数
while (interval >= 1) {
//循环体为插入排序算法
for (let i = interval; i < length; i++) {
//从interval开始往后依次排序
let temp = arr[i];
let j = i;
while (temp < arr[j - interval] && j - interval >= 0) {
arr[j] = arr[j - interval];
//步进表达式
j -= interval;
}
arr[j] = temp;//移动法
}
//步进表达式
interval = Math.floor(interval / 2);
}
return arr;
}
归并排序
归并排序使用了分治的思想。
- 归:把数组分成两半,再递归地对子数组进行分操作,直到分成一个个单独的数
- 并:把两个数合并为有序数组,再对有序数组进行合并,直到全部子数组合并为一个完整数组
function mergeSort(arr) {
console.log(main(arr));
function main(arr) {
//在数组分解为单个元素后返回,防止无限递归导致callstack溢出
if (arr.length === 1) return arr;
//分解数组,递归下可分成单个元素
let mid = Math.floor(arr.length / 2);
let left = arr.slice(0, mid);
let right = arr.slice(mid);
//分解完后合并
//arguments对象里的callee属性是指向arguments对象所在函数的指针
//arguments.callee(left) == main(left)
return merge(arguments.callee(left), arguments.callee(right));
}
//合并函数
function merge(left, right) {
let il = 0;
let rl = 0;
let result = [];
//同时遍历左右两个数组,直到有一个指针超出范围
while (il < left.length && rl < right.length) {
if (left[il] < right[rl]) {
result.push(left[il++]);
} else {
result.push(right[rl++]);
}
}
return result.concat(left.slice(il)).concat(right.slice(rl));
}
}
var arr = [8, 7, 6, 5, 4, 3, 2, 1, 10, 9];
var a = mergeSort(arr);