文/高向敏
(鎮(zhèn)江第一外國語學校 江蘇省鎮(zhèn)江市 212000)
通俗地來講,算法就是做某件事情或解決某一問題的方法、步驟、過程和程序,而算法優(yōu)化是指對算法的有關性能進行優(yōu)化。舉個例子,大家熟知的田忌賽馬的故事,在之前的比賽中,田忌總是以上等馬對上等馬,中等馬對中等馬,下等馬對下等馬,齊威王每一個等級的馬都要比田忌的強,所以田忌總是輸;后來孫臏給田忌出了個主意:比賽時,讓他以下等馬對齊威王的上等馬,再以上等馬對他的下等馬,最后以中等馬對他的下等馬。比賽結束,田忌以三局兩勝的戰(zhàn)績取得了勝利。同樣的馬匹,僅僅調換了比賽順序,就得到了反敗為勝的結果。從算法角度看,每場比賽的賽馬次序編排都是一種算法,而孫臏的策略就是一種經過優(yōu)化的算法。
同一問題可用不同算法解決,而一個算法的質量將影響到算法、程序直至軟件的工作效率。衡量算法性能的主要指標有時間復雜度、空間復雜度、正確性、健壯性等。就單純編程競賽來說,競賽要求每題的每個測試點數據應在1s內出運算結果,也就是基本語句的運算次數應該控制108以內,因此對于問題規(guī)模較大的題目,對算法進行合理優(yōu)化是必不可少的;就宏觀應用來說,假若將一個大的程序運用到實際生產生活中時,算法的執(zhí)行效率將直接影響了生產效率,特別是,大數據時代到來,算法要處理的數據數量級越來越大,處理問題的場景也愈加千變萬化,因此,為提升算法的效率,對算法進行優(yōu)化也是必不可少的環(huán)節(jié)。
人們使用計算機處理問題時,首先要對實際問題進行抽象,運用數學思想創(chuàng)建數學模型,進而設計出解決的算法,然后再進行編程、測試、調整,這是一個實際問題運用計算機得以解決的過程。從這一過程可以看出,創(chuàng)建數學模型是前提,數學模型能夠有效的把復雜的問題變簡單,化繁為簡,將一些復雜程度較高的、難以實現的編程問題,轉化成單一的、便于運算的數學結構。因此,在進行算法優(yōu)化分析時首要的就是要發(fā)揮數學理論知識的優(yōu)勢,構建數學模型,在此基礎上設計并優(yōu)化算法,求得問題的有效解決方式。數學建模不僅密切了數學、算法與計算機編程的關系,同時也直接影響了算法的正確性與性能。
當我們建立好數學模型后,將實際問題抽象化為單一簡單的數學結構的時候,數學算法的使用對于計算機編程而言是必不可少的,是實現計算機編程算法優(yōu)化的重要途徑。如早期的數學算法代表——歐幾里德算法,又名輾轉相除法,是為了求得最大公約數的一種遞回算法,每一步計算的輸出值就是下一步計算時的輸人值,這樣的算法在處理大數時效率很高,也是計算復雜性理論的開篇。再如秦九韶算法、更相減損術、中國剩余定理等等,這些數學算法對編程算法優(yōu)化都有著重大意義。除了諸如上述的經典數學算法之外,重要的數學方法如歸納法、演繹法等,或是程序設計者自己綜合運用數學知識,充分挖掘實際問題中蘊含的數量關系,所尋找的數學規(guī)律、推導的數學公式、得出的數學結論,都是算法優(yōu)化的重要途徑。在此基礎上設計的算法,往往使得原本難以解決的問題得以解決,原本已解決的問題得以高效解決。

圖1:各因子對應關系

圖2

圖3:行列值與所在圈數之間的關系圖

圖4
總之,數學思想是連接問題與算法的一座橋梁,有些問題利用這座橋可以更為方便快捷地往返于河兩岸,而還有一些問題,如果不利用這座橋可能根本無法到達河的對岸,因此,借助數學思想分析問題是進行算法優(yōu)化的重要途徑。
下面結合編程教學中的幾個具體實例,踐析數學思想在算法優(yōu)化中的應用策略。
求n以內的完全數。

表1:不同方法運行時間比較

表2

表3
完全數(Perfect number),又稱完美數或完備數,是一些特殊的自然數。它所有真因子(即除了自身以外的約數)的和,恰好等于它本身。第一個完全數是6(1+2+3=6),第二個完全數是28 (1+2+4+7+14=28)。若求n內的完全數,需要對2-n以內的每個數判斷是否是完全數(1不是完全數),因此本題關鍵在于如何判斷一個數i是否是完全數。對于這個問題可以用不同的數學方法來解決。
方法一:最直接的方法,從1到i-1每個數依次判斷其是否是i的真因子,若是則累加求和至sum,若sum=i,則說明i是完全數。
方法二:根據數學常識,對于某一整數i來說,其最大因子為i/2,在i/2~i-1范圍內沒有數據可以整除此數。據此,我們可以把遍歷范圍縮小至1~i/2,這樣程序效率可提高一倍。
方法三:進一步思考,若j是i的一個因子,則i/j一定也是i的因子,若已知1,2,4,5,10是100因子,相應地即可得出100,50,25,20,10也是其因子(如圖1所示),據此,我們可以把遍歷范圍縮小至1~即可。
方法三改進:sqrt函數一個求平方根的庫函數,函數調用有一定的時間損耗,其次,內部是浮點數運算,效率也不高,乘法的效率比除法要高的多,因此我們對循環(huán)結束條件又做了一部分改進(j*j<=i),程序效率會大大提高。
為了更加直觀對比各算法的運行效率,我們分別對其進行了n=10000,以及n=1000000的測試,程序運行時間對比如表1。
利用簡單的數學常識,縮小數據范圍,對程序的局部進行優(yōu)化,如對程序循環(huán)次數簡化等,從而達到提高程序工作效率的目的。
一個n行n列的螺旋矩陣可由如下方法生成:從矩陣的左上角(第1行第1列)出發(fā),初始時向右移動;如果前方是未曾經過的格子,則繼續(xù)前進,否則右轉;重復上述操作直至經過矩陣中所有格子。根據經過順序,在格子中依次填入 1,2,3,...,n2,便構成了一個螺旋矩陣。圖2是一個 n = 4 時的螺旋矩陣。現給出矩陣大小 n 以及i和j,請你求出該矩陣中第i行第j列的數是多少。
方法一:最直接解法,建立一個二維數組a依次存放各個矩陣數據,然后輸出a[i][j]的值即可。而當n=30000時,需要建立30000*30000的二維數組,結果會發(fā)生數據溢出且超出內存上限。
方法二:我們可采用類似貪吃蛇的方法,讓它在n*n個方格內自外向內逐格移動,控制其右轉的方向,直到到達i行j列位置,整個過程中移動步數即為求解值。
方法三:在上一個方法中,若遇到極端情況——當n=30000時候,求第15001行15000列的數是多少,需要移動次數為900000000,顯然太慢,因此我們需要進一步優(yōu)化。考慮到貪吃蛇總是從外圍一圈圈地向目的地前進,而每一圈剛好是一個正方形,我們可以先計算外圍各圈正方形的周長之和,再讓貪吃蛇從目的地所在圈的的左上角出發(fā),計算其從出發(fā)地到目的地的長度就可以了。鑒于此,我們需要尋找如下幾個數學規(guī)律:
(1)第i行j列位于第幾圈(假設為第x圈)
(2)前x-1圈,每一圈有多個數字;
(3)第i行j列位于第x圈的第幾個。
由圖3得數學規(guī)律:第i行第j列的所在的圈數x一定是(i,j,n+1-i,n+1-j)這四個數中的最小值;第1圈有(n-1)*4個數字,第2圈有(n-3)*4個數字,……,則第k圈有(n-2*k+1)*4個數字;我們只需要從所在x圈的左上角(x,x)位置出發(fā),走到目的地(i,j)即可,最多走一圈,各算法效率比較如表2所示。
建立數學模型,尋找各數據之間內在的數學關系,歸納數學規(guī)律,在此次基礎上優(yōu)化算法,往往大大提高算法性能。
如圖4,一條狹長的紙帶被均勻劃分出了n個格子,格子編號從1到n。每個格子上都染了一種顏色colori(用[1,m]當中的一個整數表示),并且寫了一個數字numi。
定義一種特殊的三元組:(x,y,z),其中 x,y,z 都代表紙帶上格子的編號,這里的三元組要求滿足以下兩個條件:(1) x,y,z都是整數,x 方法一:最直接的解法,根據x,y,z的關系 y-x=z-y,雙重循環(huán)枚舉x,y,當滿足條件colorx=colorz時求得該三元組分數并累加起來。 方法二:方法一中如果n數值較大時,非常慢,因此需要充分挖掘數據之間的關系,本題我們可以借助數學公式推導:根據題意可知,三元組的分數僅與x,z有關,與y無關.假設編號為x1,x2,x3的元素彼此間都符合題目要求的2個條件,則它們必定奇偶性相同、顏色相同。我們假設同顏色元素個數k=3,則其三元組分數之和表示為: 因此,我們只需要找出每一種顏色下編號同為奇數三元組分數之和、編號同為偶數三元組分數之和即可。如表3所示。 充分挖掘問題中的數據關系,借助數學公式推導,得出結論,并在結論基礎上從整體架構、設計算法,從而提高算法性能,達到事半功倍的效果。 計算機的學習離不開數學理論與知識的學習和運用,數學算法是計算機編程的基礎,數學思想作為溝通問題與編程實現的一座橋梁,有著極其廣泛的應用。它不僅可以直接為解題提供思路,如果與其他算法或者思想相結合,還能夠起到很好的輔助作用。通過數學模型的建立,利用數學算法對編程邏輯進行分析設計,不斷優(yōu)化數學算法,降低其時間復雜度、空間復雜度。在你覺得“山窮水復疑無路”時,不妨用數學的角度重新審視問題,也許就會“柳暗花明又一村”。
4 結束語