VBA编程常用的排序算法计数排序
Posted VBA编程学习与实践
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VBA编程常用的排序算法计数排序相关的知识,希望对你有一定的参考价值。
七月的风,八月的雨,卑微的我喜欢遥远的你……
1,
半夜好哦,大家。
排序是数据分析与处理过程中最常见也是最重要的问题之一,搞定排序可以提升工作效率3.485626%……
看在老祝爱发红包的份上,我当然对她这话发自肺腑的相信,所以曾发过两篇推文:
Excel自带的排序功能确实已经足够强大,既能单列排序也能多列排序,既能按数值排序还能按颜色排序,甚至支持自定义规则排序,而且排序效率也非常优秀……
不过,有些情况,就不适合使用工作表排序方案了。比如……
大小不一合并单元格的情况下它会罢工。
复杂数据结构下的排序它会歇菜。
另外,毕竟这家伙是基于单元格对象的,如果咱们需要排序的数据并非存放在单元格中,它就更爱莫能助了。
比如VBA数组内部的元素如何排序?
恩,很遗憾,VBA数组并没有像其它语言那样自带排序的属性方法。
当此危难时刻,说不得咱就得自力更生,掌握点传说中编程的核心科技……排序算法了。
排序算法有很多,但复杂的咱们没闲心管,少用的我们也懒得理,所以就分享三个最常用最简单的:计数排序,冒泡排序,快速排序。
2,
先说计数排序。
为什么先说它呢?不是它长的帅,理智+帅气如我不会犯如此幼稚的错误,原因只有一个——这货最简单。
什么是计数排序呢?简单的说,就是利用数组下标来确定元素的正确位置,在数组中记录元素出现的次数,最后得出有序数据。
举个例子还是。
如下图所示,为某公司几位拥有百万年薪……小职员的考核得分表,得分范围是1~10之间的整数。
现在,我们需要把“看见星光”……也就是理智+帅气的在下了……的得分按升序排列,结果如下。
……
首先,我们根据得分的范围,也就是最低分1,最高分10,建立一个数组。
Redim r(1 to 10)
如此一来,我们声明了一个数组r,里面包含10个元素。数组是有序的元素集合,因此第一个元素就是r(1),第2个元素就是r(2)……其余以此类推。
目前这个数组是空的,刚建国,一穷二白,啥都没有。
然后我们遍历数据,按号入座,把每个得分按照对应的数组索引号计入数组,并累加出现次数。
比如说7,那就是r(7)=r(7)+1
当7第一次出现时,r(7)=1
当7第二次出现时,r(7)就等于1+1,也就是2……对吧?
于是代码如下
For Each rng In [b2:g2]
n = rng.Value
r(n) = r(n) + 1
Next
数据遍历完成后,数组的情况就成了下图这样。
1、4、6、10各出现了一次,计数为1,7出现了两次,计数为2.
……
最后,我们根据数组记录的次数,依次把数据算出就OK了。
r(1)存在1次,说明数据源出现过一个1,于是我们得出一个1
r(2)为空,不管它
r(3)为空,不管它
r(4)存在1次,说明数据源出现了一个4,于是我们得出一个4
r(5)为空,不管它
r(6)存在1次,我们得出一个6
r(7)存在2次,说明数据源出现了两个7,于是我们得出7和7
……
因此最后得出升序排序结果1、4、6、7、7、10
整个过程的完整代码如下:
Sub VBACountingSort()
Dim aData, aResult, r
Dim i&, j&, n&, k&
Dim lngMin&, lngMax&
aData = Range("b2:g2").Value
'数据源装入数组adata
lngMax = Application.Max(aData)
'数据中的最小值
lngMin = Application.Min(aData)
'数据中的最大值
ReDim r(lngMin To lngMax)
'建立一个数组,范围是最小值到最大值之间,例如1 to 10
ReDim aResult(1 To UBound(r), 1 To 1)
'结果数组
For i = 1 To UBound(aData, 2)
'遍历数据,按照索引号定位数据在数组r的正确位置,并累计出现次数
n = aData(1, i)
r(n) = r(n) + 1
Next
For i = lngMin To lngMax
'正序遍历数组,也就是从小往大取值
If r(i) > 0 Then
'如果指定数组下标内有数据
For j = 1 To r(i)
'按出现次数提取数据
k = k + 1
aResult(k, 1) = i
'数据写入结果数组
Next
End If
Next
Range("j1").Resize(k, 1) = aResult
'排序后的数据写入工作表
End Sub
3,
简单说一下计数代码的扩展应用。
我们曾经使用计数排序搭配字典,实现过自定义规则排序,参考链接:
然后依然使用第一张图的数据为例,假设需要提取每个人前三名的成绩明细,结果如下图所示。你要不要动手写写代码?
4,
计数排序有以下两个局限点:
1),仅限于整数。
换个带小数点的,比如圆周率3.1415926,如果不变通的话,在数组中,按数组下标或者说索引定位,它就无处安放了。
所以,计数排序在实际应用中特别适合日期排序,毕竟在Excel中日期都是整数。
那么是不是说带小数的数值它就无能为力了呢?
比如下图所示的考试成绩表,可能包含84.5这样的小数,有几万条,能否使用计数排序?
其实是可以的。
嗯?前面不是说?
么么哒,我前面只是说如果不变通的话,带小数点的数值,计数算法它不行……
既然计数排序只能算整数,那你把小数转化成整数不就是了?84.5乘以10不就成了整数845了吗?
把数值全部统一放大十倍,也就把小数都变成了整数,计数排序后,从数组中取值时再除以10还原不就OK了??
做人不要太死板,对不对?
2),整数的跨度范围不宜过大
比如说,三个数排序,分别是1、100000、100000000,跨度范围是1到1亿之间,尽管它们是整数,但也不适合计数排序,时间和空间的复杂度都渣的一匹,大部分人的电脑估计连声明数组这步都会被警告内存不足……
那么此时我们应该怎么办呢?
如下图酱紫的,假设需要提取每个人前三收入的金额数据,怎么办?
……
——客官,不……不好意思……天太晚了……本店……本店打烊了,欲知后事如何,下次再来啊……
以上是关于VBA编程常用的排序算法计数排序的主要内容,如果未能解决你的问题,请参考以下文章