ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

[分享] 小花鹿请进。关于随机不重复抽取 算法之 【数组经典洗牌法】原理

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2012-6-21 11:18 | 显示全部楼层
本帖已被收录到知识树中,索引项:其他结构和算法
香川群子 发表于 2012-6-21 10:53
没这个必要。

原来是这样,谢谢。
还是有老师教学得快,如果我自己读帖学习,不知道什么时间才能把这个随机抽取不重复数据的问题弄明白,谢谢了。
我现在觉得能理解到80%吧。
我现在觉得理解问题也要讲究天时、地利、人和,急是急不来的,你可能对一个问题想了很长时间想不明白,那就干脆暂时放下,忽然有一个机会,你通过努力的思考可能就豁然开朗了。
很多人都是心急,学了一段时间学不好就放弃了,可能你不知道,如果你坚持,一定会学好的。

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-6-21 12:00 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
Moneky 发表于 2012-6-20 21:03
香川是否是在回答了那个抽专家的帖子,想到此贴的啊。我来凑个热闹,我能想到的只有下面几种。
1、将所有元 ...

把待抽取数组元素放入集合,然后每次随机抽取,
并从集合中删去已经抽取元素,直至全部抽取完成的代码:
  1. Sub Rnd_Collection()
  2.    
  3.     arr = [row(1:10)]
  4.     [a1:a10] = arr
  5.    
  6.     Dim s As New Collection
  7.     For i = 1 To 10
  8.         s.Add arr(i, 1)
  9.     Next i
  10.    
  11.     brr = arr
  12.    
  13.     Randomize
  14.     For i = 1 To 10
  15.         r = Int(Rnd() * s.Count) + 1
  16.             brr(i, 1) = s(r)
  17.             s.Remove r
  18.     Next
  19.    
  20.     [b1:b10] = brr
  21.    
  22. End Sub
复制代码
理解起来比较方便。

但是,由于额外使用了集合方法,要多占用内存。
另外,实际运行速度也比纯粹数组方式慢。

但数据量较大时,劣势就很明显了。

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-6-21 12:37 | 显示全部楼层
字典方法随机不重复抽取的标准代码应该是下面这样子的。
  1. Sub Rnd_Dictionary()
  2.    
  3.     arr = [a1:a10] '原始数据中可能有相同(内容重复)的元素
  4.    
  5.     Set d = CreateObject("Scripting.Dictionary")
  6.     For i = 1 To 10
  7.         d(CStr(i)) = arr(i, 1) '因此字典不能直接以元素为关键词对象,只能以序号作为唯一性关键词
  8.     Next i
  9.    
  10.     brr = arr
  11.    
  12.     Randomize
  13.     For i = 1 To 10
  14.         p = d.keys '每次重新获取有效剩余的序号关键词数组
  15.         r = Int(Rnd() * d.Count) '剩余数中随机抽取一个序号
  16.         brr(i, 1) = d(p(r)) '用字典方法返回该被抽取的序号对应的元素
  17.         d.Remove (p(r)) '从字典中删去该已经抽取的序号
  18.     Next
  19.    
  20.     [d1:d10] = brr
  21.    
  22. End Sub

复制代码
但是显然,这么用字典是绝对的浪费,字典的优点完全没有被用到。

因此效率是很低的,速度是不快的。

但思路和方法,是正确的。

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-6-21 12:51 | 显示全部楼层
原始数组随机,不重复判断,重复时重新抽取的代码:
  1. Sub Rnd_Array_Dead()
  2.    
  3.     arr = [a1:a10]
  4.    
  5.     brr = arr
  6.    
  7.     Randomize
  8.     For i = 1 To 10
  9. Redo:
  10.         r = Int(Rnd() * 10) + 1 '每次从原始数组中抽取一个位置
  11.         cnt = cnt + 1 '记录抽取次数
  12.         If arr(r, 1) = "" Then GoTo Redo '如果该位置已经为空则重新抽一次
  13.         brr(i, 1) = arr(r, 1) '抽到正确结果时存入结果数组brr
  14.         arr(r, 1) = "" '原始数组中该位置设置为空,以便对照。
  15.     Next
  16.    
  17.     [e1:e10] = brr
  18.     [e12] = cnt
  19. End Sub
复制代码
无疑这样做效率是很低的。数量较大时,往往会形成假死机。

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-6-21 12:56 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
上面这种随机抽,然后判断是否重复,有重复就再抽一次,直到抽到符合要求的元素为止……



这样的代码思路特别简单,且符合一根筋的单纯的思想。
所以很多初学者会这样用……

并且,当数据量不大时,代码在后台运行几乎也是毫无破绽地瞬间给出结果。

因此,实际上这样愚蠢的代码,居然也有很多人在用。

TA的精华主题

TA的得分主题

发表于 2012-6-21 13:04 | 显示全部楼层

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-6-21 13:06 | 显示全部楼层
本帖最后由 香川群子 于 2012-6-21 13:09 编辑

直接工作表添加辅助列,然后排序的代码:
  1. Sub Rnd_Sort()
  2.     [b1:b10] = "=Rand()" '相邻列中添加随机函数
  3.     [a1:b10].Sort [b1], 1, , , 2 '工作表排序
  4.     [b1:b10] = "" '删除辅助列
  5. End Sub
复制代码
这个工作表辅助列排序方法实际上相当棒,

但是也有先天的使用限制条件:
1. 必须在相邻位置有空列,否则无法进行。
2. 如果原始数据不在工作表中,而是VBA内存数组结果,则不是很方便。


因此,实际上很少看到有在VBA代码过程中这样去使用的例子。


TA的精华主题

TA的得分主题

 楼主| 发表于 2012-6-21 13:17 | 显示全部楼层
尤其是,如果需要在特别的位置得到排序结果,并且需要保留排列前原始数据顺序原样不变的话,
工作表排序就比较地不太令人放心了……

因为工作表中数据位置略有变化,就可能影响到代码的地址准确性。


所以,对VBA代码有一定功力的人,基本上不会采用这种做法。

TA的精华主题

TA的得分主题

发表于 2012-6-21 13:24 | 显示全部楼层
香川群子 发表于 2012-6-21 12:56
上面这种随机抽,然后判断是否重复,有重复就再抽一次,直到抽到符合要求的元素为止……

没肉吃而又饿了,就不能再等肉了,先用小米填饱肚子再说,然后努力的挣钱买肉。

TA的精华主题

TA的得分主题

发表于 2012-6-21 13:53 | 显示全部楼层
在这个帖里问个其它的问题:
我现在对常用的VBA语句和函数、字典、数组掌握的程度自认为是及格水平以上吧,那么下一步要在哪些重点的地方下功夫?谢谢。
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-5-20 01:23 , Processed in 0.031479 second(s), 6 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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