开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 170|回复: 7
打印 上一主题 下一主题
收起左侧

[易语言纯源码] 混合归并排序 不固定步长 和龙虾写的

[复制链接]
结帖率:75% (3/4)
跳转到指定楼层
楼主
发表于 7 小时前 | 只看该作者 |只看大图 回帖奖励 |正序浏览 |阅读模式   福建省福州市
分享源码
界面截图: -
是否带模块: -
备注说明: -
本帖最后由 APPLEUFO 于 2026-6-13 15:02 编辑

只能用于整数型,想用与 文本型  改改就是了  

原来的归并是固定步长   现在不固定     对完全方向相反,最差情况有奇效 ,可用直接反转数组完事

混合归并排序原理
一句话概括
首趟扫描找自然段边界,后续轮次复用边界做归并,不再重新扫描。

三个阶段
1. 扫描自然段(只做一次,O(n))

从左到右扫一遍数组,遇到 a > a[i+1] 就是一个"降序断点",说明前面的自然升序段结束了。把每个段的起始下标存到 游标首[],结束下标存到 游标尾_[]。

比如 [3,7,12, 5,9, 2, 6,8,15, 1,4,10] 一趟扫完,分段计数 = 5,每个段的边界都记录好了。

2. 快速判断(O(1))

扫描完看分段计数:

分段计数 = 1 → 整个数组已经升序,直接返回
分段计数 = 个数 → 每个元素自成一档,说明完全降序,反转即可
这两个极端场景不用归并,白捡 O(n) 甚至 O(1) 的性能。

3. 多轮归并(核心循环)

每轮做的事:

合并循环:步长为 2 遍历分段,相邻两段调 子程序_合并4 做两路归并。落单的段(奇数个分段时最后那个)传 右首=0, 右尾=0,子程序检测到直接 内存拷贝 复制过去不合并。
边界更新循环:同样步长为 2,游标首[m1] = 游标首[n1](新段头 = 左段头),游标尾_[m1] = 游标尾_[n1+1](新段尾 = 右段尾)。落单的段尾就是它自己的尾。
分段计数变成 (分段计数+1) \ 2(大概减半)
局变_源是临时 取反,切换源/目标数组
4. 双缓冲交替写入

关键优化:不每轮全数组拷贝。用 参数_数组 和 临时_归并 两个数组交替当源和目标:

第1轮:原数组 → 临时数组
第2轮:临时数组 → 原数组
第3轮:原数组 → 临时数组
...
最后如果数据落在临时数组里,用 参数_数组 = 局变_临时_归并 一次性拷回。

和其他归并排序的区别
普通归并        自然归并        混合归并
初始分段        固定步长1        扫描自然段        扫描自然段
后续轮次        步长翻倍        重新扫描        复用边界
完全升序        O(n log n)        O(n)        O(n)
完全随机        O(n log n)        O(n log n) + 扫描        O(n log n)
额外开销        无        每轮O(n)扫描        只1次扫描 + 边界数组
混合归并 = 自然归并的发现能力 + 普通归并的扫描效率。首趟扫描利用了数据的自然有序性(少段就少合并),后续轮次不再扫描又省掉了自然归并每轮 O(n) 的额外开销。






  
窗口程序集名保 留  保 留备 注
程序集8   
子程序名返回值类型公开备 注
排序模块_混合归并排序4 
参数名类 型参考可空数组备 注
参数_数组整数型
参数_升序逻辑型
变量名类 型静态数组备 注
局变_个数整数型 
局变_分段计数整数型 
局变_游标首整数型0
局变_游标尾_整数型0
局变_开始位置整数型 
局变_临时_归并整数型0
局变_源是临时逻辑型 
n1整数型 
m1整数型 
局变_个数 = 取数组成员数 (参数_数组)
如果真 (局变_个数 ≤ 1)
返回 ()
重定义数组 (局变_临时_归并, 假, 局变_个数)
重定义数组 (局变_游标首, 假, 局变_个数)
重定义数组 (局变_游标尾_, 假, 局变_个数)
如果真 (是否为空 (参数_升序))
参数_升序 = 真
' ── 第1轮:扫描自然段边界 ──
局变_分段计数 = 1
局变_开始位置 = 1
循环判断首 ()
局变_游标首 [局变_分段计数] = 局变_开始位置
局变_游标尾_ [局变_分段计数]子程序_计算尾部 (参数_数组, 局变_游标首 [局变_分段计数])
局变_开始位置 = 局变_游标尾_ [局变_分段计数] + 1
如果 (局变_开始位置 > 局变_个数)
跳出循环 ()
局变_分段计数 = 局变_分段计数 + 1

循环判断尾 ()
' ── 快速判断 ──
如果 (局变_分段计数 = 1)
如果 (参数_升序 = )
返回 ()
数组模块_反转数组_整数型 (参数_数组)
返回 ()

如果 (局变_分段计数 = 局变_个数)
如果 (参数_升序 = )
数组模块_反转数组_整数型 (参数_数组)
返回 ()
返回 ()

' 继续归并

' ── 后续轮:两两归并,复用边界 ──
局变_源是临时 = 假
判断循环首 (局变_分段计数 > 1)
' ── 第1个循环:只做合并 ──
变量循环首 (1, 局变_分段计数, 2, n1)
如果 (局变_源是临时 = )
子程序_合并4 (参数_数组, 局变_临时_归并, 局变_游标首 [n1], 局变_游标尾_ [n1], 局变_游标首 [n1 + 1], 局变_游标尾_ [n1 + 1])
子程序_合并4 (局变_临时_归并, 参数_数组, 局变_游标首 [n1], 局变_游标尾_ [n1], 局变_游标首 [n1 + 1], 局变_游标尾_ [n1 + 1])

变量循环尾 ()
' ── 第2个循环:只更新边界数组 ──
m1 = 1
变量循环首 (1, 局变_分段计数, 2, n1)
局变_游标首 [m1] = 局变_游标首 [n1]
局变_游标尾_ [m1] = 局变_游标尾_ [n1 + 1]
如果真 (局变_游标尾_ [m1] = 0)
局变_游标尾_ [m1] = 局变_游标尾_ [n1]
m1 = m1 + 1
变量循环尾 ()
' ── 清零:防止下一轮读到旧数据 ──
局变_游标首 [m1] = 0
局变_游标尾_ [m1] = 0
局变_分段计数 = m1 - 1
局变_源是临时 = 取反 (局变_源是临时)
判断循环尾 ()
' ── 最终数据在临时数组,拷回原数组 ──
如果真 (局变_源是临时 = )
参数_数组 = 局变_临时_归并

子程序名返回值类型公开备 注
子程序_合并4  
参数名类 型参考可空数组备 注
参数_源整数型
参数_目标整数型
参数_左首整数型
参数_左尾整数型
参数_右首整数型
参数_右尾整数型
变量名类 型静态数组备 注
局变_i整数型 
局变_j整数型 
局变_写整数型 
' ── 落单:右首=0 右尾=0,直接拷贝左段然后返回 ──
如果 (参数_右首 = 0 参数_右尾 = 0)
内存拷贝_数组到数组 (参数_目标 [参数_左首], 参数_源 [参数_左首], (参数_左尾 - 参数_左首 + 1) × 4)
返回 ()


' ── 正常合并两段 ──
局变_i = 参数_左首
局变_j = 参数_右首
局变_写 = 参数_左首
循环判断首 ()
如果 (局变_i > 参数_左尾)
跳出循环 ()
如果 (局变_j > 参数_右尾)
跳出循环 ()



如果 (参数_源 [局变_i] ≤ 参数_源 [局变_j])
参数_目标 [局变_写] = 参数_源 [局变_i]
局变_i = 局变_i + 1
参数_目标 [局变_写] = 参数_源 [局变_j]
局变_j = 局变_j + 1
局变_写 = 局变_写 + 1
循环判断尾 ()
' ── 左段剩余 ──
判断循环首 (局变_i ≤ 参数_左尾)
参数_目标 [局变_写] = 参数_源 [局变_i]
局变_i = 局变_i + 1
局变_写 = 局变_写 + 1
判断循环尾 ()
' ── 右段剩余 ──
判断循环首 (局变_j ≤ 参数_右尾)
参数_目标 [局变_写] = 参数_源 [局变_j]
局变_j = 局变_j + 1
局变_写 = 局变_写 + 1
判断循环尾 ()
子程序名返回值类型公开备 注
子程序_计算尾部整数型 
参数名类 型参考可空数组备 注
参数_数组整数型
参数_游标首整数型
变量名类 型静态数组备 注
n1整数型 
如果 (参数_游标首 + 1 > 取数组成员数 (参数_数组))
返回 (参数_游标首)


变量循环首 (参数_游标首, 取数组成员数 (参数_数组) - 1, 1, n1)
如果 (参数_数组 [n1] ≤ 参数_数组 [n1 + 1])

返回 (n1)

变量循环尾 ()
返回 (取数组成员数 (参数_数组))


  
DLL命令名返回值类型公开备 注
内存拷贝_数组到数组 
DLL库文件名:
kernel32.dll
在DLL库中对应命令名:
RtlMoveMemory
参数名类 型传址数组备 注
目标首元素整数型, 传目标数组[1]等,自动得到jz
源首元素整数型, 传源数组[1]等,自动得到jz
长度整数型, 拷贝的字节数


排序.zip

199.24 KB, 下载次数: 5, 下载积分: 精币 -2 枚

评分

参与人数 1精币 +1 收起 理由
kyo9766 + 1 感谢分享,很给力!~

查看全部评分


签到天数: 2 天

8
发表于 半小时前 | 只看该作者   江苏省连云港市
感谢分享
回复 支持 反对

使用道具 举报

结帖率:0% (0/1)

签到天数: 3 天

7
发表于 1 小时前 | 只看该作者   湖北省十堰市
真值得学习,感谢!......
回复 支持 反对

使用道具 举报

结帖率:100% (15/15)

签到天数: 1 天

6
发表于 3 小时前 | 只看该作者   广东省佛山市
        感谢分享,很给力!~
回复 支持 反对

使用道具 举报

结帖率:80% (4/5)
地下
发表于 5 小时前 | 只看该作者   山东省潍坊市
已经顶贴,感谢您对论坛的支持!
回复 支持 反对

使用道具 举报

结帖率:100% (3/3)

签到天数: 11 天

地板
发表于 5 小时前 | 只看该作者   山东省青岛市
可以学习一下原理,感谢分享
回复 支持 反对

使用道具 举报

签到天数: 8 天

板凳
发表于 6 小时前 | 只看该作者   河北省石家庄市
感谢分享
回复 支持 反对

使用道具 举报

结帖率:86% (6/7)

签到天数: 13 天

沙发
发表于 7 小时前 | 只看该作者   广东省深圳市
支持一下
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报QQ: 793400750,邮箱:wp@125.la
网站简介:精易论坛成立于2009年,是一个程序设计学习交流技术论坛,隶属于揭阳市揭东区精易科技有限公司所有。
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备2025452707号) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

快速回复 返回顶部 返回列表