归并排序是一种高效、稳定的排序算法,它的基本原理是分治法(Divide and Conquer)。这意味着它将一个大问题分解成几个较小的问题,然后分别解决这些小问题,最后将所有小问题的解决方案合并成最终解决方案。
下面是归并排序的基本步骤:
- 将数组分成两半。
- 对每一半进行归并排序。
- 合并两个已排序的数组。
我们将从一个简单的示例开始,然后逐步深入到算法实现的细节。
示例:
假设我们有一个整数数组 [5, 3, 8, 4, 2]
。我们可以将这个问题分解成以下步骤:
- 将数组分成两半:
[5, 3]
和[8, 4, 2]
。 - 对每一半进行归并排序:
- 对
[5, 3]
进行归并排序:得到[3, 5]
。 - 对
[8, 4, 2]
进行归并排序:得到[2, 4, 8]
。
- 对
- 合并已排序的数组:
[3, 5]
和[2, 4, 8]
合并为[2, 3, 4, 5, 8]
。
现在让我们开始实现这个算法。
实现:
首先,我们需要一个函数来分割数组。这个函数接受一个数组和两个索引作为参数,返回从第一个索引到第二个索引(包括)的元素组成的子数组。
function splitArray(array, start, end) {
return array.slice(start, end + 1);
}
接下来,我们需要一个函数来合并两个已排序的数组。这个函数会从两个数组中选择最小的元素,然后将它们连接在一起。
function merge(left, right) {
let result = [];
let leftIndex = 0;
let rightIndex = 0;
while (leftIndex < left.length && rightIndex < right.length) {
if (left[leftIndex] < right[rightIndex]) {
result.push(left[leftIndex]);
leftIndex++;
} else {
result.push(right[rightIndex]);
rightIndex++;
}
}
return result.concat(left.slice(leftIndex)).concat(right.slice(rightIndex));
}
最后,我们可以实现归并排序函数。这个函数接受一个数组作为输入,返回一个新的已排序数组。
function mergeSort(array) {
if (array.length <= 1) {
return array;
}
const middle = Math.floor(array.length / 2);
const left = splitArray(array, 0, middle - 1);
const right = splitArray(array, middle, array.length - 1);
return merge(mergeSort(left), mergeSort(right));
}
现在我们可以使用 mergeSort
函数对数组进行排序:
const unsortedArray = [10,6,7,1,3,9,4,2];
const sortedArray = mergeSort(unsortedArray);
console.log(sortedArray); // 输出:[1,2,3,4,6,7,9,10]
归并排序是一种非常有用的排序算法,因为它是稳定的(相同的元素保持原来的顺序)且时间复杂度为 O(n log n),在很多情况下都是一个很好的选择。
快速排序
快速排序基于大小的比较,分成较大区域和较小区域,可以进一步提升排序算法性能
具体实现如下
const quickSort = (arr) => {
if (arr.length <= 1) {
return arr;
}
const pivotIndex = Math.floor(Math.random() * arr.length);
const pivot = arr[pivotIndex];
const left = [];
const right = [];
for (let i = 0; i < arr.length; i++) {
if (i === pivotIndex) {
continue;
}
if (arr[i] < pivot) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
return [...quickSort(left), pivot, ...quickSort(right)];
}
测试一下性能
const arr = [];
for (let i = 0; i < 10000; i++) {
arr.push(Math.random() * 10000);
}
const start = performance.now();
quickSort(arr);
const end = performance.now();
console.log(`Execution time: ${end - start} milliseconds`);
10000条数据排序,仅用了 20ms,还是很快的
算法复杂度分析,最大的缺点不稳定