一:归并排序;
核心思路:
不断的折半拆分,以 数组长度 / 2 为数组中间值拆分为左侧数组和右侧数组。
不断递归继续拆分已经拆分出来的左侧数组和右侧数组
直到满足递归结束条件:拆分出来的数组的长度为 1。
让每次递归结束返回的数组是有序的:
设置临时数组,比较左右侧数组首元素的大小,较小的首元素移除数组推入到临时数组当中。
改变原数组。
// 1.折半拆分数组--直到把数组每个元素都单独抽离拆分出来
// 2.对拆分出来的俩个单独的数组元素进行排序,合并成一个有序小数组
// 递归以上步骤,直到将所有单独数组元素合并成一个数组
Array.prototype.mergeSort = function () {
// 递归函数
const rec = (arr) => {
// 递归结束条件:拆分成单独数组时递归结束
if (arr.length === 1) return arr;
// 折半拆分
const mid = Math.floor(arr.length / 2);
// 拆分的左侧数组
const left = arr.slice(0, mid);
// 拆分的右侧数组
const right = arr.slice(mid, arr.length);
// 递归继续拆分
const orderLeft = rec(left);
const orderRight = rec(right);
// 将拆分的单个数组元素进行排序
const res = [];
while (orderLeft.length || orderRight.length) {
if (orderLeft.length && orderRight.length) {
// 犯错的点:
// 推入左拆分数组或者右拆分数组的头元素,同时是要删除掉数组头元素的
// 因为这俩个左右拆分数组是要不断循环最后合并成一个顺序数组的
res.push(orderLeft[0] < orderRight[0] ? orderLeft.shift() : orderRight.shift());
} else if (orderLeft.length) {
res.push(orderLeft.shift());
} else if (orderRight.length) {
res.push(orderRight.shift());
}
}
return res;
}
rec(this).forEach((n, i) => {
this[i] = n;
})
}
const arr = [5,4,38,8,1,2,2,1];
arr.mergeSort();
console.log(arr);
二:快速排序
随便以数组的某一个元素为基准(方便起见所以以数组第一个元素为基准),比基准元素小的加入到新左侧数组当中,比基准元素大的加入到新右侧数组当中。
不断让新左侧数组和右侧数组递归以上方法,每次都要将 左侧数组 基准值 右侧数组 拼接成一个数组。
Array.prototype.quickSort = function () {
const rec = (arr) => {
// 递归结束条件
if(arr.length <= 1) return arr;
// 以随机选定的数组的某一个元素为基准,划分左右区间
const left = [];
const right = [];
// 选取数组第一个为基准
const mid = arr[0];
// 根据基准划分左右区间
for (let i = 1; i < arr.length; i++) {
if (mid > arr[i]) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
// 递归调用并进行数组拼接
return [...rec(left), mid, ...rec(right)];
}
const res = rec(this);
// 改变原数组
res.forEach((n, i) => {
this[i] = n;
})
}
//const arr = [2,4,5,3,1]
const arr = [8,2,4,5,3,1,1,11,8,22]; // l:2 4 5 4 1 1; m:8; r: 11 8 22
arr.quickSort();
console.log(arr);