
本文深入探讨了J*aScript归并排序(Merge Sort)实现中常见的几个关键错误,包括归并操作中临时数组回写时的索引错位、边界参数`right`的语义不一致以及次优的中间点计算方式。通过详细分析问题并提供优化后的代码示例,旨在帮助开发者构建健壮、高效且符合J*aScript编程习惯的归并排序算法。
归并排序(Merge Sort)是一种高效的、稳定的排序算法,其核心思想是“分而治之”。它将一个大问题分解为若干个小问题,然后将小问题的解合并起来得到大问题的解。具体到排序,就是:
在给定的J*aScript归并排序代码中,存在几个关键问题导致其无法正常工作并产生 undefined 值。
这是导致输出 [undefined, undefined, ..., 3, 5] 的直接原因。在 merge 函数的最后一步,将 temp 数组中的排序结果拷贝回原数组 arr 时,使用了错误的索引逻辑:
// 原始错误代码段
for (let i = left; i <= right; i++) {
arr[i] = temp[i]; // 错误:temp数组是从索引0开始填充的
}temp 数组是从索引 0 开始填充的,其有效元素范围是 0 到 k-1。然而,上述代码却尝试使用 arr 的原始索引 i(从 left 到 right)来访问 temp 数组。当 left 不为 0 时,temp[left] 可能越界(undefined),或者访问到 temp 中不正确的位置。
修正方案: 正确的回写逻辑应该将 temp 数组中的元素从其起始位置 0 开始,依次拷贝到 arr 数组中从 left 开始的位置。
// 正确的临时数组回写逻辑
for (let idx = 0; idx < k; idx++) {
arr[left + idx] = temp[idx];
}这里,idx 用于遍历 temp 数组的有效范围 [0, k-1],而 left + idx 则确保这些元素被放置到 arr 数组中正确的起始位置。
Kreado AI
Kreado AI是一个多语言AI视频创作平台,只需输入文本或关键词,即可创作真实/虚拟人物的多语言口播视频。 为创作者提供AI赋能
182
查看详情
在许多编程语言和库中,处理数组或列表的范围时,有两种常见的索引约定:
原始代码的 mergesort 函数内部,循环条件如 i
最佳实践: 在J*aScript等语言中,将 right 参数定义为半开区间的“超尾”索引(即不包含在范围内的第一个索引)是更常见和推荐的做法。这与 Array.prototype.slice() 等内置方法的行为一致,并且简化了循环条件(通常从 i
如果采用半开区间语义:
中间点 mid 的计算: 原始代码使用 let mid = parseInt((right - left) / 2) + left; 来计算中间点。使用 parseInt 和浮点除法再转换的方式效率较低。 优化: 使用位运算 >> 1 进行整数除法更高效:let mid = left + ((right - left) >> 1);。
merge 函数中的冗余拷贝: 原始 merge 函数在主 while 循环结束后,有两个 for 循环用于拷贝剩余元素:
for (; i <= mid; i++) { temp[k] = arr[i]; k++; }
for (; j <= right; j++) { temp[k] = arr[j]; k++; }在采用半开区间语义的 merge 逻辑中,如果
i 已经达到 mid,说明左半部分已处理完毕,剩余的元素都在右半部分。如果 j 已经达到 right,说明右半部分已处理完毕,剩余的元素都在左半部分。
一个常见的优化是:当其中一个子数组的所有元素都已拷贝到 temp 后,如果另一个子数组还有剩余元素,这些剩余元素本身就已经是排序好的,并且它们在原数组中的位置相对于已合并的部分是正确的。因此,只需将未完全拷贝的那个子数组的剩余元素拷贝到 temp 即可。在某些实现中,甚至可以省略拷贝右半部分剩余元素到 temp 的步骤,因为它们在原数组中的相对顺序已经正确,后续的 temp 回写操作会覆盖 arr[left] 到 arr[left+k-1] 的部分,而 arr[j] 之后的元素保持不变。
综合上述分析和优化,以下是修正并遵循J*aScript惯例的归并排序实现:
/**
* 归并排序主函数
* @param {Array<number>} arr 待排序数组
* @param {number} left 数组范围的起始索引 (包含)
* @param {number} right 数组范围的结束索引 (不包含, 超尾)
*/
function mergesort(arr, left, right) {
// 当子数组长度大于1时才需要排序
if (right - left > 1) {
// 计算中间索引,使用位运算进行高效的整数除法
// mid 将是左半部分的超尾索引,也是右半部分的起始索引
let mid = left + ((right - left) >> 1);
// 递归排序左半部分 [left, mid)
mergesort(arr, left, mid);
// 递归排序右半部分 [mid, right)
mergesort(arr, mid, right);
// 合并两个有序子数组
merge(arr, left, mid, right);
}
}
/**
* 合并两个有序子数组
* @param {Array<number>} arr 原数组
* @param {number} left 左子数组的起始索引
* @param {number} mid 左子数组的超尾索引,也是右子数组的起始索引
* @param {number} right 右子数组的超尾索引
*/
function merge(arr, left, mid, right) {
let i = left, // 左子数组的当前索引
j = mid, // 右子数组的当前索引
k = 0; // 临时数组的当前索引
let temp = []; // 临时数组用于存储合并结果
// 比较并合并左右两个子数组的元素,直到其中一个子数组遍历完毕
while (i < mid && j < right) {
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
// 将左半部分剩余元素拷贝到临时数组
// 如果左半部分还有剩余,说明右半部分已经全部拷贝
while (i < mid) {
temp[k++] = arr[i++];
}
// 注意:如果右半部分有剩余(即 j < right),
// 它们已经相对有序地存在于原数组中,并且在合并后的结果中,
// 这些元素将位于 temp 数组回写操作覆盖范围之外,
// 或者它们会被 temp 数组的以上就是J*aScript归并排序实现:常见陷阱与优化指南的详细内容,更多请关注其它相关文章!
相关文章:
msn官网入口地址手机版 msn官方网站手机最新链接
在Google App Engine Go中实现独立模块代码库与灵活路由
快手极速版在线观看 官方网页版登录地址
机构:以往存储涨价周期小米利润率实际上有所改善 能转嫁给消费者等
如何让 composer 信任自签名的 HTTPS 证书源?
J*aScript设计模式实践_j*ascript代码优化
百度网盘网页版入口 百度网盘网页版官方登录网址
Composer的 archive 命令怎么用_快速打包你的PHP项目及其Composer依赖
C++如何实现异步操作_C++11使用std::future和std::async进行异步编程
铁路12306的积分有效期是多久_铁路12306积分有效期说明
快手网页版在线登录 快手网页版官网入口快速访问
魅族17怎样用浏览器译外语网页_iPhone魅族17浏览器译外语网页【即时翻译】
b站怎么看视频的弹幕数量_b站弹幕数量查看方法
sublime如何配置Python开发环境_将sublime打造成轻量级Python IDE
excel怎么制作工资条 excel快速生成工资条的方法
J*aScript中如何高效提取对象指定属性
PowerPoint如何制作滚动字幕结尾彩蛋_PowerPoint路径动画实现平滑滚动字幕效果
Django表单提交验证失败后保持字段值不刷新
Lar*el 递归关系中排除指定分支的教程
c++如何使用Meson构建系统_c++比CMake更快的构建工具
ArrayList与LinkedList核心操作的Big-O复杂度分析
MAC如何安全彻底地删除文件_MAC使用终端命令确保文件无法被恢复
护手霜蹭到袖口上了如何清洗? 怎样避免留下一圈油印?
谷歌浏览器无痕模式怎么开 Chrome开启无痕浏览设置方法【教程】
使用Python高效删除Word宏并转换DOCM为DOCX格式
小红书网页版入口链接分享 小红书官网直接进
J*a最大堆Heapify方法修复:索引计算与边界条件深度解析
Win10系统服务哪些可以禁用 Win10安全优化服务列表【干货】
Golang如何使用context实现超时取消_Golang context超时取消模式实践
如何创建独立于主系统的J*a运行环境_隔离式环境搭建策略
QQ邮箱官方网站登录入口_QQ邮箱网页版在线使用
php源码怎么看淘宝客系统_看php源码淘宝客系统技巧
UC浏览器官网入口2025最新 UC浏览器网页版正式地址
cad如何更改注释性对象的比例_cad注释性比例调整方法
PHP 枚举:根据字符串获取枚举案例的策略与实现
Win11怎么设置鼠标指针速度_Win11提高鼠标指针精确度选项
俄罗斯浏览器官网直达链接 俄罗斯浏览器最新在线入口导航
Composer的 COMPOSER_PROCESS_TIMEOUT 配置项有什么用_解决因执行时间过长而失败的Composer脚本
Yandex浏览器官方网页版入口 Yandex浏览器最新版官网
在Go Martini框架中高效服务动态生成图像的实践指南
AO3官网镜像链接 Archive of Our Own同人文在线浏览
天眼查怎么看公司融资情况 天眼查企业融资历史查询步骤【攻略】
解决Rails应用中内容错位与Turbo警告:meta标签误用导致富文本渲染异常
wps文字怎么插入目录并自动更新_wps文字如何插入目录并自动更新方法
J*aScript中向JSON对象添加新属性的正确姿势
蛙漫官网漫画入口地址_蛙漫在线畅读无广告弹窗
蛙漫漫画免费阅读入口_蛙漫官方正版无广告纯净版
如何有效阻止外部脚本意外修改内联样式的高度属性
Golang并发任务中错误如何聚合_Golang goroutine error收集方式
在J*a中如何在J*a中使用异常机制记录错误日志_异常日志实践经验