三种常见的 JavaScript 排序算法

本文介绍了三种常见的排序算法——冒泡排序、选择排序和归并排序,以及如何在JavaScript中实现它们。冒泡排序和选择排序的时间复杂度为N^2,适合小数据集;归并排序则更高效,适用于大数据。文章详细展示了每种排序算法的实现过程和逻辑,并提供了JavaScript代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天,为大家介绍三种常见的排序算法:冒泡排序选择排序归并排序。我将列举它们的用途,以及如何在 JavaScript 中实现它们。

排序介绍

当我们考虑排序时,我们会考虑数字的排序或按字母顺序对字符串进行排序,或者在现实世界中,我们可能会考虑按身高、年龄等对人进行排序。在面试环境中,当我们被问及关于排序,我们可以假设它是关于一个数字数组。通常,我们需要编写一些代码来获取这些数字,并将它们从最小最大排序

[3, 8, 5, 9, 1, 2] -> [1, 2, 3, 5, 8, 9]

如果您是 JavaScript 开发人员,可能会想到sort()数组方法。

console.log([3, 8, 5, 9, 1, 2].sort());
// [ 1, 2, 3, 5, 8, 9 ]

根据您使用的浏览器,此内置sort()方法的底层算法会有所不同。浏览器有不同的JavaScript 引擎,这是一种执行 JavaScript 代码的方式。例如,Chrome 使用V8 引擎,而 Mozilla Firefox 使用SpiderMonkey。Mozilla 使用归并排序,而 V8 使用Timsort(本文不讨论)。

我们如何在不使用内置方法的情况下实现我们自己的排序列表的sort()方法?

让我们看一下一些常见的排序算法。

时间复杂度

 

查看最坏情况下的运行时间,我们发现冒泡排序和选择排序都有N^2运行时间。这意味着对于添加到要排序的数字集合中的每个额外元素,算法将花费更多的时间来运行。这意味着冒泡排序和选择排序是用于大型数据集的糟糕算法。但是,如果您正在处理较小的数据集,并且您知道它仍将是一个小数据集,那么使用这些算法没有任何问题。

一般来说,当我们考虑排序算法时,我们通常会假设最坏的情况n*log(n)

使用 JavaScript 进行冒泡排序

冒泡排序是一种排序算法,它逐个元素地循环遍历输入列表,将当前元素与后面的元素进行比较,并在需要时交换它们的值。它实际上不是一个有用的算法,除了用于介绍排序算法的目的之外——由于它的简单性。

冒泡排序是使用 JavaScript 解决问题的更简单的方法之一。我们将从以下代码开始:

function bubbleSort(arr) {
  // your code here
}
bubbleSort([3, 4, 9, 5, 1]);

查看输入,我们看到arr,它是数组的缩写。arr将是一个数字数组。与我们将在本文中实现的所有算法一样,我们的目标是将这个数字数组从最小到最大排序

我们要采取的第一步是遍历数组。

function bubbleSort(arr) {
  for (let i = 0; i < arr.length; i++) {}
}
bubbleSort([3, 4, 9, 5, 1]);

我们使用经典for循环来访问数组中每个位置的索引和元素。

接下来,我们要编写一个内部 for 循环,它将从索引 0 开始循环,一直循环到数组的长度。数组长度总是从索引偏移 1,因为数组的索引为 0,因此-1将确保我们的代码不会在不应该迭代的地方迭代。

function bubbleSort(arr) {
  for (let i = 0; i < arr.length; i++) {
    for (let j = 0; j < arr.length - i - 1; j++) {}
  }
}
bubbleSort([3, 4, 9, 5, 1]);

在我们的for循环中,我们将要编写一些逻辑来检查数组中的当前元素和下一个元素。

if (arr[j] > arr[j + 1]) {
  const lesser = arr[j + 1];
  arr[j + 1] = arr[j];
  arr[j] = lesser;
}

if声明内容如下:if the current element at the current index is greater than the next one,我们将在此处交换值。

注意:最后一步不需要自己的代码块。当然,我们会想要return排序的数组。检查下面的完整实现。

实施

function bubbleSort(arr) {
  for (let i = 0; i < arr.length; i++) {
    for (let j = 0; j < arr.length - i - 1; j++) {
      if (arr[j] > arr[j + 1]) {
        const lesser = arr[j + 1];
        arr[j + 1] = arr[j];
        arr[j] = lesser;
      }
    }
  }
  // return the sorted array
  return arr;
}

console.log(bubbleSort([3, 4, 9, 3, 1]));

使用 JavaScript 进行选择排序

选择排序是一种就地比较排序算法,具有n^2时间复杂度,正如我们上面所说,这使得它在大型项目列表上效率低下。它以简单着称,并且在特定情况下确实比复杂算法具有性能提升。

选择排序动画。红色是电流最小值。黄色是排序列表。蓝色是当前项目。资料来源:维基百科。

为了了解如何实现这个算法,让我们稍微考虑一下。我们知道我们需要比较数组中的元素,所以我们可能需要两个for循环。

该算法的第一步是for在整个数组中运行一个外部循环:

function selectionSort(arr) {
  for (let i = 0; i < arr.length; i++) {}
}

我们还想声明一个变量,indexMin并将其分配给i假设它是数组中的最小元素

function selectionSort(arr) {
  for (let i = 0; i < arr.length; i++) {
    let indexMin = i;
  }
}

接下来,我们将设置另一个for循环来验证indexMin确实是数组中的最小元素,但是if我们看到一个元素更少,我们将通过存储它来记录它的索引indexMin,如下所示:

for (let j = i + 1; j < arr.length; j++) {
  if (arr[j] < arr[indexMin]) {
    indexMin = j;
  }
}

我们算法的最后一步是检查是否indexMin等于i。请记住,我们假设这i是上面的最低值。如果它们不相等,它们将被交换。

if (indexMin !== i) {
  let lesser = arr[indexMin];
  arr[indexMin] = arr[i];
  arr[i] = lesser;
}

就是这样。我们有一个选择排序的实现。但不要忘记——最后一步是return数组 ( arr)。请参阅下面的完整实现。

实施

function selectionSort(arr) {
  for (let i = 0; i < arr.length; i++) {
    let indexMin = i;

    for (let j = i + 1; j < arr.length; j++) {
      if (arr[j] < arr[indexMin]) {
        indexMin = j;
      }
    }

    if (indexMin !== i) {
      let lesser = arr[indexMin];
      arr[indexMin] = arr[i];
      arr[i] = lesser;
    }
  }

  return arr;
}
console.log(selectionSort([3, 4, 9, 3, 1]));

使用 JavaScript 合并排序

Merge Sort 是John Von Neumann发明的一种算法,他是一位杰出的数学家、物理学家、计算机科学家、工程师和博学家。与上述两种算法不同,归并排序是一种高效的通用排序算法。它通过递归排序(我们在这篇 Fibonacci 文章中稍微介绍了递归)将数组分成多个较小的数组,这些数组经过排序然后组合它们。我们将使用两个独立的函数,它们都有不同的用途。

简而言之,归并排序:

  1. 将未排序的列表分成 n 个子列表,每个子列表包含一个元素(一个元素的列表被认为是已排序的)。
  2. 重复合并子列表以产生新的排序子列表,直到只剩下一个子列表。这将是排序列表。

归并排序的一个例子。资料来源:维基百科。

提示:合并排序是Cracking the Coding Interview 的作者Gayle Laakmann McDowell推荐了解的必备算法之一。

让我们看看如何在 JavaScript 中实现归并排序。

第 1 步:合并

主要功能mergeSort()将进行递归调用,因此我们不会逐行输入此算法,而是要分别研究每个功能 - 因为代码很棘手且很难理解。

merge()比较简单,我们先来看一下。

请注意,merge()接受两个参数,leftrightleft并且right是两个单独的排序数组值。本质上,我们merge()函数的目标是获取这两个排序数组并将它们合并在一起。

您可能已经在考虑实现这一目标的方法。如果您想声明一个变量并将其设置为一个空数组,那么您就走对了!让我们看一下merge()函数。

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

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

  return [...results, ...left, ...right];
}

稍微检查一下上面的代码块。这里没有发生太复杂的事情,函数也不包含太多代码。让我们尝试运行它。将代码保存到可以运行的地方,console.log(merge([3, 2, 1], [9, 2, 3]))在函数后面添加。如果你运行这个,你会看到两个数组,leftright已经合并,返回一个单一的数组:[ 3, 2, 1, 9, 2, 3 ]

为了更好地理解我们的代码在上面做了什么,这些链接可能对您有用:

第二步:归并排序

到目前为止,我们已经实现了算法的一部分。是时候通过实施来完成它了mergeSort()

在您花一些时间了解该merge()功能后,请查看下面的功能,mergeSort()。这就是事情会变得混乱的地方。

// mergeSort()
function mergeSort(arr) {
  if (arr.length === 1) {
    return arr;
  }

  const center = Math.floor(arr.length / 2);
  const left = arr.slice(0, center);
  const right = arr.slice(center);

  return merge(mergeSort(left), mergeSort(right));
}

首先,让我们实际测试一下我们的代码。

console.log(mergeSort([4, 3, 2, 1]))->[ 1, 2, 3, 4 ]

它有效,但这是怎么回事?

如果我们放慢速度并稍微考虑一下,我们就会发现我们必须获取arr参数,将其拆分为两个,然后将其传递给merge()函数(但只有在没有任何东西可以拆分时)。

让我们看看这三个变量在做什么。

const center = Math.floor(arr.length / 2);
const left = arr.slice(0, center);
const right = arr.slice(center);

console.log(center, left, right);
// 2 [ 4, 3 ] [ 2, 1 ]
// 1 [ 4 ] [ 3 ]
// 1 [ 2 ] [ 1 ]

所以,正如我们上面所说,我们的代码应该将数组分成两半,直到它不能再这样做为止,此时数组将被传递给merge()函数。由于数组中只有 4 个元素,因此它将在中间拆分一次,然后在left和上再次拆分right。我们将剩下[4, 3]and [2, 1],它将作为 传递到 merge 中merge([4, 3], [2, 1])

递归本身就很混乱,我们知道这个算法可能会让你摸不着头脑。但需要一些时间来试验它。研究它,甚至记住它。

实施

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

  const center = Math.floor(arr.length / 2);
  const left = arr.slice(0, center);
  const right = arr.slice(center);

  return merge(mergeSort(left), mergeSort(right));
}

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

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

  return [...results, ...left, ...right];
}
console.log(mergeSort([3, 4, 9, 3, 1]));

结论

这是一篇很长的文章,如果您已经读到这里,请拍拍自己的背!我们探索了三种不同的排序算法,并用 JavaScript 编写了它们。您可能还想查看许多其他排序算法,例如快速排序插入排序等等。您可以在网络的其他区域探索它们。您还可以在右侧订阅我们的时事通讯,以便在我们编写更多有关 JavaScript 算法的文章时保持更新。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值