vba算法
㈠ VBA洗牌法原理谁能文字阐释一下
我找了此资料,一起共享
下面直接介绍【经典数组洗牌法】的算法原理:
假如你有一个布袋或者抽屉,里面有m=10个不同号码的球,
你要随机抽取,并保证不重复……
那么正确的做法是:
1.每次从布袋中随机抽取一个球;注意到rnd()函数的正确抽取目数应该是=m
2.抽取出来的这一个球要另外放置开;
【如果不另外放置,而只是记下号码后再把球返回布袋,接下来就无法保证这个已经被抽到过的球又被重复抽到。】
而这个,就是1楼代码中没有考虑到而产生的重大bug
3.继续从布袋中随机抽取另一个球;
注意到此时布袋中剩余球的数量少了一个是m-1了,因此rnd()函数的正确抽取目数应该是=m-1
4.抽取出来的这第2个球和已经抽取出来的第1个球放置在一齐,并且按新的序列排放。
5.重复以上随机抽取过程,注意到关键是:
a.每次抽取的母数即剩余球数要递减1个
b.每次抽取出来的新球要分开放置,不能放回布袋!
c.新抽取出来的球,要和前面已经取出的球按新的序列整齐排放。
d.剩下最最重要一点,但是看到这里好多人都可能不会意识到的一个问题:
布袋中剩余球如何放置?
即,假定布袋中球也是像放置在抽屉中那样,有序地排放着的,
那么每次抽走一个球,必然留下一个空格……【这就很麻烦了!】
因为大家知道,实际上数组中用rnd()函数只能是返回一个一定区间内的值及数组位置,
而如果留有空位的话,随机性就无法保证高效……万一抽到空格怎么办?难道重新再抽一次?
如果抽到只剩最后一个求时,则原先的布袋/抽屉中,将留下9个空格,则每次随机函数的计算结果,将有90%的概率仍旧抽到空格……
这就完蛋了。
【经典数组洗牌法】的真正原理是:
1.从m个值中【随机确定一个位置r】(利用Rnd()随机函数计算,具体算法是【以剩余数m为母数】区间进行随机值计算并取整返回位置)
2.把这个位置即要被抽取的元素(球)先取出拿在手中【存入临时变量t】,【腾出一个空位】。
3.把数组的【第1位置】(Lbound)元素拿出来,【放入刚才腾出的r空位】。并随即【腾出】了数组第一位置作为【新的空位】
(也可以以数组的最末位置(UBound)作为开始位置进行处理,具体算法代码就不太一样了)
4.把上述第2步骤取出的、存入了临时变量t的元素(球),准确地放入【新的空位】,即数组第一位置。
这个数组第一位置中的【新元素】,就是已经被有效抽取的第1个不重复值。
然后,继续
1.抽第2个数时,以剩余母数m-1作为随机计算区间而返回一个随机值并计算取整返回第2个不重复的随机位置r
2.把这个位置r即要被抽取的第2个元素(球)先取出拿在手中【存入临时变量t】,【腾出一个空位】。
3.把数组的【第2位置】元素拿出来,【放入刚才腾出的r空位】。并随即【腾出】了数组第2位置作为【新的空位】
(也可以以数组的最末倒数第2位置进行处理,具体算法代码就不太一样了)
4.把上述第2步骤取出的、存入了临时变量t的元素(球),准确地放入【新的空位】,即数组第2位置。
这个数组第2位置中的【新元素】,就是已经被有效抽取的第2个不重复值。
以上述方式反复进行,抽取、置换,存放,直到最后一个,也不会产生重复抽取了。
下面是【经典数组洗牌法】实际代码中最简单的代码例子:
对于一个下标1开始的一维数组,从中随机抽取n个元素返回。
SubGetRnd(arr,n)
Randomize
Fori=1Ton'正序洗牌1ton简化代码
r=Int(Rnd()*(n-i+1))+i
t=arr(r):arr(r)=arr(i):arr(i)=t'下标1开始一维代码
Next
EndSub
'正序洗牌1ton简化代码详解:
SubGetRnd(arr,n)
Randomize'随机种子初始化,保证每次代码运行或打开文件时出现的随机序列是和上次文件保存/运行时不同的序列。
Fori=1Ton'遍历1ton
r=Int(Rnd()*(n-i+1))+i、
'按每次剩余母数(n-i+1)作为随机计算区间,计算Rnd()*(n-i+1)然后用int()函数去整,得到剩余数中的随机位置。
'紧接着,这个随机位置后面【+i】处理,转化成从新的起点i开始的随机位置r。即不再包括已经抽取出的结果,避免重复。
t=arr(r)'把这个随机位置r中的元素取出,存入临时变量t
arr(r)=arr(i)'把【第i个】位置中的元素【放入刚才腾出的r空位】(实际数据操作时并没有腾出,而只是用新的值直接覆盖掉。)
arr(i)=t'把上面刚刚【腾出的i空位】放入刚才存放在临时变量t中的当前最新抽取元素,完成一次抽取过程。
Next'循环抽取、置换、存贮抽取结果
EndSub
㈡ VBA高手解析这一段递归组合算法看不懂
Subzuhe(x%,z%,sr$,ggAsByte)'x新加的数字序号,z原有的数字总和,sr算式,gg原有个数
Ifz+arr(x,1)=hAndgg=g-1Then'和与个数都符合
k=k+1
arr1(k,1)=sr&arr(x,1)&"="&h
ExitSub
EndIf
Ifx<UBound(arr)Andz<hThen'没到最后一个数且和还不足
Ifz+arr(x,1)<hThen'和不足'本行疑似有误,改为Ifgg<g-1Then应省时
zuhex+1,z+arr(x,1),sr&arr(x,1)&"+",gg+1'增加一个数
EndIf
zuhex+1,z,sr,gg'取下一个数
EndIf
EndSub
㈢ Excel VBA 插入多行的4种方法 & 算法对比
本文提供了通过Excel VBA插入多行的四种方法,并对每种方法的算法效率进行了对比。以插入500行为例,来分析不同方法的性能和效率。
方法1(普通):最直观但也是最慢的方法,即一行一行地插入。插入500行大约需要27.34375秒,效率低下。算法复杂度为O(n),即与行数线性相关。
方法2(算法):这种方法利用算法加快插入速度,相较于方法1快得多,大约需要0.5390625秒。算法复杂度为O(logN+1),其中N为行数,故插入500行的复杂度约为9。尽管速度提升显着,但并非最优。
方法3(最快):使用了VBA中的Range.Resize()方法,实现插入行操作只需一行代码,速度非常快,只需0.078125秒。从算法角度看,复杂度为O(1),即与行数无关。但应注意,插入行数增加时,操作时间会相应增加。
方法4(便利):利用Range().EntireRow.Insert和Rows().Insert方法实现插入行,代码简洁,速度同样为0.078125秒。复杂度也为O(1),与行数无关。此外,此方法还允许指定插入行的起始位置,增加了便利性。
总结,文中介绍的方法虽然简单,但通过这些代码,可以清晰地理解算法的效率和Big O表示法的概念。面向初学者,希望本文能帮助大家理解和掌握VBA中的高效插入方法。