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中的高效插入方法。