跳到主要内容

排序

QuickSort

要实现快速排序,我们需要定义一个方法去递归地对数组进行分区操作,将比基准值小的放在基准值的左边,将比基准值大的放在基准值的右边

基准值一般选择数组第一个、最后一个、中间或随机位置的数据

快速排序算法的性能在很大程度上取决于基准元素的选择策略。当做分区操作的基准元素被选中时,如果它恰好是中间值,这样每次分区操作都会把数组分成两个几乎相等的部分,这种情况下,快速排序的时间复杂度为O(nlogn)。考虑到所有可能的数组排列,快速排序的平均时间复杂度也是O(n log n)。如果每次分区选取的基准元素是最小或者最大的元素,这将导致不平衡的分区,一个子数组将几乎是空的,而另一个子数组包含n-1个元素,这会导致递归调用的深度直接相关于数组的大小,最坏时间复杂度退化为 O(n^2)

function quickSort(arr) {
// 如果数组长度小于 2 则无需排序,直接返回
if (arr.length < 2) {
return arr
}
// 选择最后一项作为基准值
const pivot = arr[arr.length - 1]
// 存储比基准值大的数据
const rightArr = []
// 存储比基准值小的数据
const leftArr = []
// 遍历 分组
for (let i = 0; i < arr.length - 1; i++) {
if (arr[i] < pivot) {
rightArr.push(arr[i])
} else {
leftArr.push(arr[i])
}
}
// 对左右两个子数组进行递归排序,并将结果与基准值拼接后返回
return [...quickSort(leftArr), pivot, ...quickSort(rightArr)]
}

Bubble Sort

冒泡排序是一种简单的排序算法,它重复地遍历要排序的列表,比较每对相邻的项目,并把顺序错误的项交换过来。

第一次會將最大的值交換到最後一個 index,接者跑第二次,將第二大的值交換到到處第二個位置,直到陣列中的所有值都由小到大依序排完。

遍历列表的工作是重复进行的,直到没有再需要交换的,这意味着列表已经排序完成。

冒泡排序算法的时间复杂度为 O(n^2),在最坏的情况下和平均情况下都是如此,因此它适用于项数不多的列表。

function bubbleSort(arr) {
let n = arr.length;

// 外循环控制所有轮次的遍历
for (let i = 0; i < n - 1; i++) {
// 假设数组已经排序,用于后面检查是否有元素交换
let swapped = false;

// 内循环控制每轮的比较和交换
for (let j = 0; j < n - 1 - i; j++) { // - i确保了内层循环每次只处理数组中尚未排序的部分
// 比较相邻元素
if (arr[j] > arr[j + 1]) {
// 交换元素
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
// 如果发生了交换,则标记为true
swapped = true;
}
}

// 如果这一轮没有发生交换,说明数组已经是排序好的,可以结束循环
if (!swapped) {
break;
}
}

return arr;
}

Selection Sort

首先在未排序序列中找到最小(或最大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(或最大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

选择排序的时间复杂度是 O(n^2),与冒泡排序相同,因为它也使用了两个嵌套循环遍历数组的元素。

function selectionSort(arr) {
let n = arr.length;

for (let i = 0; i < n - 1; i++) {
// 找到从i到n-1范围内最小元素的索引
let minIndex = i;
for (let j = i + 1; j < n; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j; // 更新最小元素的索引
}
}
// 如果最小元素不是当前位置,交换这两个元素
if (minIndex != i) {
[arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
}
}

return arr;
}