用 JavaScript 实现归并排序

目录

归并排序背后的逻辑

用 JavaScript 实现归并排序

归并排序的效率

总结


归并排序背后的逻辑

归并排序使用分而治之的概念对给定的元素列表进行排序。它将问题分解为较小的子问题,直到它们变得足够简单以至可以直接解决为止。

以下是归并排序的步骤:

  1. 将给定的列表分为两半(如果列表中的元素数为奇数,则使其大致相等)。
  2. 以相同的方式继续划分子数组,直到只剩下单个元素数组。
  3. 从单个元素数组开始,合并子数组,以便对每个合并的子数组进行排序。
  4. 重复第 3 步单元,直到最后得到一个排好序的数组。

以数组 [4, 8, 7, 2, 11, 1, 3] 为例,让我们看一下归并排序是如何工作的:

image.png

用 JavaScript 实现归并排序

首先实现一个将两个已排序子数组合并为一个已排序数组的函数 merge() 。要注意着两个子数组是已经被排好序的,这一点非常重要, merge() 函数只用于其进行合并。

可以通过遍历这两个子数组来实现:

function merge(left, right) {
  let arr = [];
  // 如果任何一个数组为空,就退出循环
  while (left.length && right.length) {
    // 从左右子数组的最小元素中选择较小的元素
    if (left[0] < right[0]) {
      arr.push(left.shift());
    } else {
      arr.push(right.shift());
    }
  }

  // 连接剩余的元素,防止没有把两个数组遍历完整
  return [...arr, ...left, ...right];
}

在这个函数中,通过把两个排好序的子数组(leftright)合并来获得一个排好序的大数组。首先,创建一个空数组。之后在 left 和 right 两个子数组中最小元素中的较小的一个,并将其添加到空数组。我们只需要检查 left 和 right 子数组中的第一个元素,因为它们是已排好序的。

在这个过程中,从子数组中删除了被选择的元素(通过 shift() 函数实现)。继续这个过程,直到其中一个子数组变为空。最后把非空子数组的剩余元素(因为它们已经被排序)插入主数组的最后面。

现在有了合并两个已排序数组的代码,接下来为实现归并排序算法的最终代码。这意味着要继续分割数组,直到最终只包含一个元素的数组为止:

function mergeSort(arr) {
  if (arr.length < 2) {
    return arr;
  }

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

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

在代码中先确定中点,并用 splice() 函数将数组分为两个子数组。如果元素数量为奇数,则左侧的元素数量会少一个。不断的划分数组,直到剩下单个元素的数组(array.length < 2)。然后用之前实现的 merge() 函数合并子数组。

代码实现后用前面的用例测试一下:

array = [4, 8, 7, 2, 11, 1, 3];
console.log(mergeSort(array));

输出符合预期:

1,2,3,4,7,8,11

归并排序的效率

归并排序的最差时间复杂度为 $O(n\\log n)$,与快速排序的最佳情时间复杂度相同。归并排序是目前最快的排序算法之一。

与快速排序不同,归并排序不是in-place排序算法,这意味着除了输入数组之外,它还会占用额外的空间。这是因为我们使用了辅助数组来存储子数组。归并排序的空间复杂度为 $O(n)$。

归并排序的另一个优点是非常适合多线程,因为每个被划分出的一半都可以单独排序。另一种常见的减少归并排序运行时间的方法是在到达相对较小的子数组时(大约 7 个元素)使用插入排序。这是因为插入排序在处理小型或几乎排好序的数组时表现非常好。

总结

在本文中,我们了解了Merge Sort算法背后的逻辑,并用 JavaScript 实现。它是基本排序算法之一,可以帮助我们更好的了解分治法策略。

  • 12
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,我可以回答这个问题。以下是用 JavaScript 实现归并排序的代码: function mergeSort(arr) { if (arr.length <= 1) { return arr; } const mid = Math.floor(arr.length / 2); const left = arr.slice(, mid); const right = arr.slice(mid); return merge(mergeSort(left), mergeSort(right)); } function merge(left, right) { const result = []; let i = ; let j = ; while (i < left.length && j < right.length) { if (left[i] < right[j]) { result.push(left[i]); i++; } else { result.push(right[j]); j++; } } return result.concat(left.slice(i)).concat(right.slice(j)); } const arr = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]; console.log(mergeSort(arr)); // [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9] ### 回答2: 归并排序是一种常见的排序算法,基于分治策略的思想。下面是用JavaScript实现归并排序的代码: ``` function mergeSort(arr) { if (arr.length <= 1) { return arr; } const middle = Math.floor(arr.length / 2); const left = arr.slice(0, middle); const right = arr.slice(middle); return merge(mergeSort(left), mergeSort(right)); } function merge(left, right) { let result = []; let lIndex = 0; let rIndex = 0; while (lIndex < left.length && rIndex < right.length) { if (left[lIndex] < right[rIndex]) { result.push(left[lIndex]); lIndex++; } else { result.push(right[rIndex]); rIndex++; } } return result.concat(left.slice(lIndex)).concat(right.slice(rIndex)); } // 测试代码 const arr = [4, 2, 6, 8, 1, 3, 5, 7]; const sortedArr = mergeSort(arr); console.log(sortedArr); ``` 这段代码实现归并排序的逻辑。`mergeSort`函数是主函数,它先将数组分成两部分,然后通过递归调用`mergeSort`对左右两部分分别进行排序。最后,将左右两部分的排序结果通过`merge`函数合并成一个有序的数组。 `merge`函数接收两个已经排序的数组,在合并的过程中,每次从左右两个数组中选取较小的元素放入结果数组中。最后,将左右数组中剩余的元素依次放入结果数组即可。 例如,在测试代码中,输入数组`[4, 2, 6, 8, 1, 3, 5, 7]`经过归并排序后,输出`[1, 2, 3, 4, 5, 6, 7, 8]`。 ### 回答3: 归并排序是一种使用分治思想的排序算法,其基本思想是将原始序列分成两个较小的子序列,然后分别对子序列进行排序,最后将排好序的子序列合并成一个有序序列。 以下是使用JavaScript编写的归并排序示例代码: ```javascript // 归并排序函数 function mergeSort(arr) { if (arr.length <= 1) { return arr; // 基准条件:当数组长度小于等于1时,直接返回数组 } // 找到中间索引位置 const mid = Math.floor(arr.length / 2); // 递归分解左右两个子序列 const left = mergeSort(arr.slice(0, mid)); const right = mergeSort(arr.slice(mid)); // 合并两个有序子序列 return merge(left, right); } // 合并函数 function merge(left, right) { const merged = []; let i = 0; let j = 0; // 比较左右两个子序列的元素,将较小的元素加入 merged 数组中 while (i < left.length && j < right.length) { if (left[i] <= right[j]) { merged.push(left[i]); i++; } else { merged.push(right[j]); j++; } } // 将剩余的元素添加到 merged 数组中 while (i < left.length) { merged.push(left[i]); i++; } while (j < right.length) { merged.push(right[j]); j++; } return merged; } // 测试代码 const arr = [5, 3, 8, 4, 2, 1, 9, 6, 7]; const sortedArr = mergeSort(arr); console.log(sortedArr); ``` 以上代码首先定义了归并排序函数 `mergeSort`,该函数递归地将原始数组分解为较小的子序列,并调用 `merge` 函数将两个有序子序列合并成一个有序序列。 `merge` 函数比较左右两个子序列的元素,将较小的元素依次添加到 `merged` 数组中,最后将剩余的元素添加到 `merged` 数组中。最后,`mergeSort` 函数返回排序好的数组。 通过对测试数组 `[5, 3, 8, 4, 2, 1, 9, 6, 7]` 调用 `mergeSort` 函数,可以得到排序好的数组 `[1, 2, 3, 4, 5, 6, 7, 8, 9]`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值