ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
300集Office 2010微视频教程 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 7478|回复: 10

[原创] 排序外传——数组排序之二

[复制链接]

TA的精华主题

TA的得分主题

发表于 2012-6-14 10:02 | 显示全部楼层 |阅读模式
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖已被收录到知识树中,索引项:排序
写完了二维数组排序——http://club.excelhome.net/thread-821316-1-1.html,觉得数组排序还有很多内容,有很多特殊的排序要求,所以有了这个外传。
一、整型数组排序
在各种排序中,冒泡排序最直观,但效率却低,需要循环n*(n-1)/2次(n为排序个数),灰袍法师优化的希尔排序,循环可以达到1.25n,但其结构复杂,也同时降低了效率。对于快速排序,循环也约0.86n,但里面的小循环却要约10.4n
Dim M1, M2
Sub test1() '循环次数统计
Dim r&(1 To 10000)
For k = 1 To 100
For i = 1 To 10000
  r(i) = (10000 * Rnd)
Next
M1 = 0: M2 = 0
QSort2 r, 1, 10000
MM = MM + M1
Mn = Mn + M2
Next
MsgBox "100次平均小循环:" & MM / 100 & "平均小循环:" & Mn / 100
End Sub
Public Sub QSort2(r&(), L&, H&)
Dim i&, j&, X, y
i = L
j = H
X = r(L + 1 + Int((H - L - 1) * Rnd))
While (i <= j)
  While (r(i) < X And i < H) ’小循环
    M1 = M1 + 1
    i = i + 1
  Wend
  While (X < r(j) And j > L) ’小循环
    M1 = M1 + 1
    j = j - 1
  Wend
  If (i <= j) Then
    y = r(i)
    r(i) = r(j)
    r(j) = y
    i = i + 1
    j = j - 1
  End If
Wend
M2 = M2 + 1
If (L < j) Then QSort2 r, L, j
If (i < H) Then QSort2 r, i, H
End Sub
对于整型数组的排序,其实还有更好的方法。先看下面一段程序:
sub test
dim b(9)
a=array(4,1,7,2,9,0,5,8,6,3)
for i=0 to 9
         b(a(i))=a(i)
next
msgbox join(b)
end sub
    只一层循环,也不必对数组元素进行交换,即可对数组进行排序,效率可以说是最高的,但其特点是数组元素是整型,不重复连续的序列,适应性不高,优化如下:   
Public Sub IntSort(a&(), Optional Ord%)
    Dim i&, j&, Ma&, Mi&, L&, U&, b&()
    L = LBound(a)
    U = UBound(a)
    Ma = a(L)
    Mi = Ma
    ReDim c(L To U + 1)
    For i = L + 1 To U
      If a(i) > Ma Then Ma = a(i)
      If a(i) < Mi Then Mi = a(i)
    Next
    ReDim b(Mi To Ma + 1)
    For i = L To U
      b(a(i)) = b(a(i)) + 1
    Next
    If Ord Then
      n = U
      For i = Mi To Ma
        For j = 1 To b(i)
          a(n) = i
          n = n - 1
        Next
      Next
      Else
      n = L
      For i = Mi To Ma
        For j = 1 To b(i)
          a(n) = i
          n = n + 1
        Next
      Next
    End If
    End Sub
    虽然上面进行了三个循环,对于数组值区间和数组元素数目相接近的时候,总的循环量约为3n,但每个循环都非常简单,效率也是很高,以100万个1~10^6数据测试,比快速排序快约8倍。以以100万个1~10^7数据测试,结果也是本程序快。
结论:对于整型数组,数组区间比数组元素数目小10倍并且内存允许,用本程序排序是最好的。本程序的一个很好应用实例是成绩排名,参考:
http://club.excelhome.net/thread-689873-6-1.html
二、序列排序
EXCEL自带排序中有一个是按序列排序,可惜序列的数目非常少,象是不可以超过1000个,确也有限,也想做一个按序列排序,想来想去,除了用字典外,确实想不出有什么好办法:
Public Sub XLSort(a(), x(), Optional Ord%)
Dim d As New Dictionary, i&, j&, n&, b&()
For Each c In x  
  n = n + 1
  d(c) = n
Next
ReDim b(n)
L = LBound(a)
U = UBound(a)
For i = L To U
  t = d(a(i))
  b(t) = b(t) + 1
Next
If Ord Then
  For i = 1 To n
    For j = 1 To b(i)
      a(U) = d(i)
      U = U - 1
    Next
  Next
  Else
  For i = 1 To n
    For j = 1 To b(i)
      a(L) = d(i)
      L = L + 1
    Next
  Next
End If
Set d = Nothing
End Sub
三、文本数字混合排序
日常中经常有一种按如下的序列:
DN20XXXDN25XXXDN32XXXDN40XXXDN50XXXDN100XXXDN125XXXDN150XXX
如若按照文本排序,却得到如下结果:
DN100XXXDN125XXXDN150XXXDN20XXXDN25XXXDN32XXXDN40XXXDN50XXX
非常不爽,这种排序的处理只能分解为DN20XXX,按多KEY二维数组排序处理。代码从略。
排序外传.rar (23.99 KB, 下载次数: 412)

点评

如果自定义排序的时候,自定义和其他的在一起,按KEY是否存在,分成两个数组,分别排?  发表于 2012-7-6 11:21

评分

2

查看全部评分

TA的精华主题

TA的得分主题

发表于 2012-6-14 10:26 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
好东西,学习了

TA的精华主题

TA的得分主题

发表于 2012-6-14 10:29 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2012-6-14 10:34 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2012-6-14 14:39 | 显示全部楼层
本帖最后由 mjzxlmg 于 2012-6-14 14:40 编辑

速度是挺快的。但是只能整数性,限制了使用范围,改进下就完美了。

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-6-15 09:33 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
mjzxlmg 发表于 2012-6-14 14:39
速度是挺快的。但是只能整数性,限制了使用范围,改进下就完美了。

本来就是为整型数组写的,利用数组有序的下标作排序,如用改进?

TA的精华主题

TA的得分主题

发表于 2012-6-15 10:25 | 显示全部楼层
Zamyi 发表于 2012-6-15 09:33
本来就是为整型数组写的,利用数组有序的下标作排序,如用改进?

如果用*100000000000的方法是否可行呢?这样一般情况下应该可以满足了。能否行得通呢?

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-6-15 11:12 | 显示全部楼层
mjzxlmg 发表于 2012-6-15 10:25
如果用*100000000000的方法是否可行呢?这样一般情况下应该可以满足了。能否行得通呢?

你看了序列排序没有?不得已用字典引用索引,效率肯定没有普通排序快。

TA的精华主题

TA的得分主题

发表于 2012-9-2 16:13 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2015-1-12 20:07 | 显示全部楼层
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

关闭

最新热点上一条 /1 下一条

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

GMT+8, 2024-4-23 19:35 , Processed in 0.051123 second(s), 13 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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