ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
12
返回列表 发新帖
楼主: 香川群子

[原创] QuickSort 快速排序算法应用 返回数组第k个大小的值

[复制链接]

TA的精华主题

TA的得分主题

发表于 2014-10-15 08:42 | 显示全部楼层
本帖已被收录到知识树中,索引项:排序
to 香川老师,我的一维下料优化问题,您是怎么做出来的,能教下我吗?期待。多谢!
http://club.excelhome.net/home.p ... =thread&view=me

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-4-24 11:50 | 显示全部楼层
研究了一下,进一步开发得到如下QuickSort排序算法:

对于一维数组,返回排序后在k1~k2区间内的值,但并不需要对全部元素进行排序。
(区间内的值,可以排序,也可以不排序。)

用法:
当数据量极大,但仅仅需要提取少部分数据,且无需精确排序时非常有用、高效。
  1. Function QuickSort(tr, l&, u&, k1&, k2&, Optional z& = 0) 'A-Z
  2.     Dim i&, j&, r, t
  3.     i = l: j = u: r = tr((l + u) \ 2)
  4.     Do
  5.         Do While i < u
  6.             If tr(i) < r Then i = i + 1 Else Exit Do
  7.         Loop
  8.         Do While j > l
  9.             If tr(j) > r Then j = j - 1 Else Exit Do
  10.         Loop
  11.         If i < j Then t = tr(i): tr(i) = tr(j): tr(j) = t: i = i + 1: j = j - 1 Else If i = j Then i = i + 1: j = j - 1: Exit Do Else Exit Do
  12.     Loop
  13.     If z Then
  14.         If k1 < j + 1 Then If j > l Then Call QuickSort(tr, l, j, k1, k2, z)
  15.         If k2 > i - 1 Then If i < u Then Call QuickSort(tr, i, u, k1, k2, z)
  16.         If k1 = k2 Then QuickSort = tr(k1)
  17.     Else
  18.         If l < k1 Then If k1 <= j Then Call QuickSort(tr, l, j, k1, k2, z)
  19.         If k1 <= l Then If l <= k2 Then If k2 < j Then Call QuickSort(tr, l, j, k1, k2, z)
  20.         
  21.         If i - 1 < k1 Then If k1 <= u Then Call QuickSort(tr, i, u, k1, k2, z)
  22.         If k1 <= i - 1 Then If i - 1 <= k2 Then If k2 < u Then Call QuickSort(tr, i, u, k1, k2, z)
  23.     End If
  24. End Function
复制代码
递归函数过程QuickSort(tr, l&, u&, k1&, k2&, Optional z& = 0)中,
第1参数 tr为待处理的一维数组。参照引用。(过程执行后源数组的顺序就会改变)
第2、第3参数 l、u 为需要排序提取的该一维数组的下标起始、结束位置。
第4、第5参数 k1、k2 为需要提取区间值的起始、结束位置。
第6参数 z 默认=0时 仅提取排序区间值,但k1~k2区间内的值仍是散乱的,没做精确排序。
z=1时,会对k1~k2区间内的值做A-Z升序排序,但其余部分是不做排序的。

区间内虽然不做排序,但区间内的值总是符合比小值区间内所有值都大、比大值区间内所有值都小。
也就是说,是把整个一维数组分为小、中、大值的三个区间,但并不对所有值进行排序的算法。


TA的精华主题

TA的得分主题

 楼主| 发表于 2016-1-17 14:38 | 显示全部楼层
本帖最后由 香川群子 于 2016-1-18 09:26 编辑

这样更好一些。
加入了<10时直接比较插入排序、提高速度效率。
另外,楼上代码在区间内不排序时排序范围有bug会造成死循环溢出堆栈、已经确认修改。

  1. Function QuickSort(tr, l&, u&, k1&, k2&, Optional z& = 0) 'A-Z
  2.     Dim i&, j&, r, t
  3. '    cnt = cnt + 1
  4.     If u - l < 10 Then
  5.         For i = l + 1 To u
  6.             r = tr(i)
  7.             For j = i - 1 To l Step -1
  8.                 If tr(j) <= r Then Exit For Else tr(j + 1) = tr(j) '<= A-Z
  9.             Next
  10.             tr(j + 1) = r
  11.         Next
  12.     Else
  13.         i = l: j = u: r = tr((l + u) \ 2)
  14.         While i < j
  15.             While tr(i) < r: i = i + 1: Wend '< A-Z
  16.             While tr(j) > r: j = j - 1: Wend 'A-Z
  17.             If i <= j Then t = tr(i): tr(i) = tr(j): tr(j) = t: i = i + 1: j = j - 1
  18.         Wend
  19. '        Debug.Print tr(k1); tr(k2); l; j; i; u; cnt
  20.         If z Then 'Sort [k1,k2]
  21.             If l < j Then If k1 <= j Then Call QuickSort(tr, l, j, k1, k2, z)
  22.              'l,k1,j,k2/k1,l,k2,j/k1,l,j,k2/ Not l,j,k1,k2
  23.             If i < u Then If i <= k2 Then Call QuickSort(tr, i, u, k1, k2, z)
  24.              'i,k1,u,k2/k1,i,k2,u/k1,i,u,k2/ Not k1,k2,i,u
  25.         Else 'No Sort [k1,k2]
  26.             If l < j Then If l < k1 Then If k1 <= j Then Call QuickSort(tr, l, j, k1, k2, z)
  27.              'l<k1,(k1<=j),(k2)
  28.             If l < j Then If k1 < l Then If k2 < j Then Call QuickSort(tr, l, j, k1, k2, z)
  29.              'k1<l,(k2<j)
  30.             
  31.             If i < u Then If i < k1 Then If u <= k2 Then Call QuickSort(tr, i, u, k1, k2, z)
  32.               '(i<k1),u<=k2
  33.             If i < u Then If i < k2 Then If k2 < u Then Call QuickSort(tr, i, u, k1, k2, z)
  34.               '(k1),(i<k2),k2<u
  35.         End If
  36.     End If
  37.     If k1 = k2 Then QuickSort = tr(k1)
  38. End Function
复制代码

TA的精华主题

TA的得分主题

发表于 2019-6-17 22:54 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 cui26896 于 2019-6-18 08:02 编辑

要是对二维数组中的一列也能做就好了。

TA的精华主题

TA的得分主题

发表于 2019-6-21 17:22 | 显示全部楼层
复制代码运行后,字符形查找第一位中间还是隔了一个D,如附件所示。
Inked运行结果_LI.jpg

TA的精华主题

TA的得分主题

发表于 2021-4-25 11:34 | 显示全部楼层
香川群子 发表于 2016-1-17 14:38
这样更好一些。
加入了

有没有按照平均值作为key中轴的代码

TA的精华主题

TA的得分主题

 楼主| 发表于 2021-4-25 12:14 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
weiliang2018 发表于 2021-4-25 11:34
有没有按照平均值作为key中轴的代码

是否采用算术平均值作为区分中轴的算法,和随机取值或取个数中间值,实际运用之后的耗时差异并没有很大。

也就是说,几乎没影响。

原因就是,不管怎么折腾,该走的步骤并不会因此减少。
因为这个是递归计算的,如果某个区段直接都是大数值或小数值,还是需要反复递归迭代计算的。

你不用在此费心了。……如果真的有显著提升效率的作用,那么多比你聪明的人,早就更改代码了。
全世界都没你聪明,是绝对不可能的。

TA的精华主题

TA的得分主题

发表于 2021-4-25 21:27 | 显示全部楼层
香川群子 发表于 2021-4-25 12:14
是否采用算术平均值作为区分中轴的算法,和随机取值或取个数中间值,实际运用之后的耗时差异并没有很大。 ...

之前1892不是有个排序算法帖子,里面有个版主发个链接说按照平均值排序,说好像更稳定了,不受已排序影响。

TA的精华主题

TA的得分主题

 楼主| 发表于 2021-4-26 19:27 | 显示全部楼层
weiliang2018 发表于 2021-4-25 21:27
之前1892不是有个排序算法帖子,里面有个版主发个链接说按照平均值排序,说好像更稳定了,不受已排序影响 ...

不可能。平均值又不是中位数。

其实效率最高的应该是中位数。
但是计算求中位数也要消耗计算时间和效率的,没有实际价值。

我已经说的很清楚了,如果确实有好处,而且不是特例(和数据本身特征有关)是普遍有效,那么代码早就改过来了。

TA的精华主题

TA的得分主题

发表于 2024-6-23 09:33 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
多谢!慢慢学习,领会中。
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-17 18:38 , Processed in 0.031400 second(s), 9 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

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