js 数组排序几种方法


方法1: sort()

`sort()` 方法是 JavaScript 数组原型的内置方法,Array.prototype.sort()用于原地对数组进行排序。默认情况下,它将数组元素作为字符串进行比较,并按照 Unicode 顺序进行排序。示例代码如下:

const numbers = [5, 1, 3, 2, 4];
numbers.sort(); // [1, 2, 3, 4, 5]
//请注意,`sort()` 方法会修改原始数组,而不是返回一个新的排序后的数组。

//若想不改变原数组可以 使用拓展运算符+解构赋值
const numbers = [5, 1, 3, 2, 4];
const sortedNumbers = [...numbers].sort((a, b) => a - b);
console.log(sortedNumbers); // [1, 2, 3, 4, 5];
//这种方法不会修改原始数组,而是返回一个新的排序后的数组。

`sort()` 方法还可以接受一个比较函数作为参数,用于自定义排序逻辑。比较函数应该返回一个负数、零或正数,分别表示两个元素的相对顺序。

const numbers = [5, 1, 3, 2, 4];
numbers.sort((a, b) => a - b); // [1, 2, 3, 4, 5]
//在上述示例中,比较函数 `(a, b) => a - b` 按升序对数字进行排序。


方法2:reverse()

Array.prototype.reverse() 方法:用于反转数组中元素的顺序。与sort() 方法是相对关系,一个正序一个倒叙。

const numbers = [5, 1, 3, 2, 4];
numbers.sort(); // 先排序 [1, 2, 3, 4, 5]
numbers.reverse(); // [5, 4, 3, 2, 1]
// `reverse()` 方法同样会修改原始数组,并返回反转后的数组。


方法3: 冒泡排序法

冒泡排序(Bubble Sort)是一种简单的排序算法,它通过多次遍历数组,比较相邻元素并交换它们的位置,将较大(或较小)的元素逐渐“冒泡”到数组的一端。冒泡排序的基本思想是重复比较相邻的元素,如果它们的顺序不正确,则交换它们,直到整个数组排序完成。

以下是使用 JavaScript 实现冒泡排序的示例代码:

function bubbleSort(arr) {
  const length = arr.length;

  for (let i = 0; i < length - 1; i++) {
    for (let j = 0; j < length - 1 - i; j++) {
      if (arr[j] > arr[j + 1]) {
        // 交换位置
        const temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
      }
    }
  }

  return arr;
}

// 示例用法
const numbers = [5, 1, 4, 2, 8];
const sortedNumbers = bubbleSort(numbers);
console.log(sortedNumbers); // [1, 2, 4, 5, 8]

在上述代码中,我们使用两个嵌套的循环来遍历数组并比较相邻元素的大小。如果前一个元素大于后一个元素,就交换它们的位置。外层循环控制遍历次数,内层循环用于比较和交换元素。通过多次循环,较大的元素会逐渐“冒泡”到数组的末尾,直到整个数组排序完成。

冒泡排序的时间复杂度为 O(n^2),其中 n 是数组的长度。尽管冒泡排序的性能较差,但由于其简单直观的实现方式,对于小型数据集来说是一个可行的选择。然而,在处理大型数据集时,更高效的排序算法如快速排序或归并排序通常更具优势。


方法4:快速排序法

快速排序(Quick Sort)是一种高效的排序算法,它采用分治的思想,通过将数组分成较小的子数组并递归地排序这些子数组,最终将整个数组排序。

以下是使用 JavaScript 实现快速排序的示例代码:

function quickSort(arr) {
  if (arr.length <= 1) {
    return arr;
  }

  const pivot = arr[Math.floor(arr.length / 2)]; // 选择中间元素作为基准点
  const less = [];  // 存放小于基准点的元素
  const equal = []; // 存放等于基准点的元素
  const greater = []; // 存放大于基准点的元素

  for (let num of arr) {
    if (num < pivot) {
      less.push(num);
    } else if (num === pivot) {
      equal.push(num);
    } else {
      greater.push(num);
    }
  }

  return [...quickSort(less), ...equal, ...quickSort(greater)];
}

// 示例用法
const numbers = [5, 1, 4, 2, 8];
const sortedNumbers = quickSort(numbers);
console.log(sortedNumbers); // [1, 2, 4, 5, 8]

在上述代码中,我们选择数组中间的元素作为基准点(pivot),然后遍历数组,将小于基准点的元素放入 less 数组,等于基准点的元素放入 equal 数组,大于基准点的元素放入 greater 数组。然后,通过递归地对 less 和 greater 数组进行快速排序,并将排序后的结果与 equal 数组合并,最终得到排序完成的数组。

快速排序的时间复杂度为平均情况下的 O(n log n),最坏情况下的时间复杂度为 O(n^2),其中 n 是数组的长度。快速排序通常比冒泡排序和插入排序等简单排序算法更快,尤其对于大型数据集的排序效率更高。它也是常用的排序算法之一,并在许多编程语言的标准库中实现。

方法5:归并排序法

归并排序(Merge Sort)是一种经典的排序算法,它基于分治(Divide and Conquer)的思想,将数组逐步划分为较小的子数组,然后递归地对子数组进行排序,最后将排序好的子数组合并成一个有序的数组。

以下是使用 JavaScript 实现归并排序的示例代码:

function mergeSort(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);

  return merge(mergeSort(left), mergeSort(right)); // 递归地对左右子数组进行归并排序,并将结果合并
}

function merge(left, right) {
  const result = [];

  while (left.length && right.length) {
    if (left[0] <= right[0]) {
      result.push(left.shift());
    } else {
      result.push(right.shift());
    }
  }

  // 将剩余的元素拼接到结果数组中
  return result.concat(left, right);
}

// 示例用法
const numbers = [5, 1, 4, 2, 8];
const sortedNumbers = mergeSort(numbers);
console.log(sortedNumbers); // [1, 2, 4, 5, 8]

在上述代码中,我们首先定义了 mergeSort 函数,它接收一个数组作为输入,并进行递归调用。如果数组的长度小于等于 1,直接返回该数组。否则,我们找到数组的中间索引,将数组分成两个子数组 left 和 right。然后,递归地对 left 和 right 子数组调用 mergeSort 函数进行排序。最后,我们调用 merge 函数将排序好的子数组合并成一个有序的数组。

merge 函数用于将两个有序的子数组合并成一个有序的数组。它使用两个指针分别指向 left 和 right 子数组的开头,比较两个指针指向的元素,将较小的元素放入 result 数组中,并将对应子数组的指针向后移动。重复这个过程,直到其中一个子数组的元素全部放入 result 数组。最后,将剩余的元素拼接到 result 数组中,即可得到最终的有序数组。

归并排序的时间复杂度是稳定的,为 O(n log n),其中 n 是数组的长度。归并排序的优点是稳定性和适用于大规模数据集,但它需要额外的存储空间来存储临时数组。


方法6:插值排序法

插值排序(Interpolation Sort)是一种排序算法,它是插入排序的一种变体。与插入排序使用固定的间隔(通常是1)来确定元素的位置不同,插值排序使用目标元素的值和数组中元素的值之间的比例来确定目标元素的位置。

以下是使用 JavaScript 实现插值排序的示例代码:

function interpolationSort(arr) {
  for (let i = 1; i < arr.length; i++) {
    const current = arr[i];
    let j = i - 1;

    // 使用插值计算目标元素的位置
    const targetIndex = interpolationSearch(arr, current, 0, j);

    // 将目标位置之后的元素向后移动
    while (j >= targetIndex) {
      arr[j + 1] = arr[j];
      j--;
    }

    // 将目标元素放入正确的位置
    arr[targetIndex] = current;
  }

  return arr;
}

function interpolationSearch(arr, target, start, end) {
  while (start <= end && target >= arr[start] && target <= arr[end]) {
    if (start === end) {
      if (arr[start] === target) {
        return start;
      }
      return -1;
    }

    const pos = start + Math.floor(((target - arr[start]) * (end - start)) / (arr[end] - arr[start]));

    if (arr[pos] === target) {
      return pos;
    }

    if (arr[pos] < target) {
      start = pos + 1;
    } else {
      end = pos - 1;
    }
  }

  return -1;
}

// 示例用法
const numbers = [5, 1, 4, 2, 8];
const sortedNumbers = interpolationSort(numbers);
console.log(sortedNumbers); // [1, 2, 4, 5, 8]

在上述代码中,我们定义了 interpolationSort 函数来执行插值排序。它使用一个循环来遍历数组,并将每个元素插入到已排序的部分中的正确位置。在插入过程中,我们使用 interpolationSearch 函数来计算目标元素的位置。

interpolationSearch 函数使用插值公式来计算目标元素的位置。它根据目标元素的值与数组中元素的值之间的比例,计算出一个估计的位置 pos。然后,根据 arr[pos] 与目标元素的关系,将搜索范围缩小,并重复这个过程,直到找到目标元素或搜索范围为空。

插值排序的时间复杂度平均情况下为 O(n log n),最坏情况下为 O(n^2),取决于目标元素的分布情况和数组的有序程度。插值排序在目标元素分布均匀、数组基本有序的情况下,具有较好的性能。然而,在某些情况下,插值排序的性能可能不如其他排序算法,如归并排序或快速排序。

总结

冒泡排序是一种简单但效率较低的排序算法,插值排序在目标元素分布均匀的情况下具有较好的性能,归并排序适用于大规模数据集但需要额外的存储空间,快速排序通常具有较好的性能但可能在最坏情况下效率较低。

选择排序算法时,需要考虑数据集的规模、数据分布情况以及对稳定性的要求。

声明:BenBonBen博客|版权所有,违者必究|如未注明,均为原创

转载:转载请注明原文链接 - js 数组排序几种方法


过去太迟,未来太远,当下最好