本文通過比較對數字指定誤差的求開平方不同算法實現之間的效率比較,來使程序入門者對不同算法的性能差距有直觀的印象,并且對算法的作用有深刻的體會。
算法一(暴力遍歷法):
/** * 求開方 * @param source 被開方數,大于等于0 * @param deviation 誤差范圍 * @return */ public static double sqrt(double source,double deviation) { if(source < 0 || deviation <0) { throw new RuntimeException("don't transmit negtive"); } long count = 1;//統計循環執行次數 double result = 0; while ((result + 1) * (result + 1) < source) { count++; result++; } while ((result + deviation) * (result + deviation) < source ) { count++; result += deviation; } System.out.PRintln("sqrt total count:" + count); return result; }本算法是將計算結果從0開始一點一點增加并進行試探,直到接近真實結果誤差范圍內。
算法二(步長調整法):
/** * 求開方 優化,步長調整 * @param source 被開方數,大于等于0 * @param deviation 誤差范圍 * @return */ public static double sqrt1(double source,double deviation) { if(source < 0 || deviation <0) { throw new RuntimeException("don't transmit negtive"); } long count = 1;//統計循環執行次數 double result = 0; int stepI = 2; double stepD = deviation; long stepCount = 1; while ((result + 1) * (result + 1) < source) { count++; stepCount++; if(stepCount%3==0){ //加快結果累計,調整步長 if((result + stepI) * (result + stepI) < source) { result += stepI; stepI++; continue; } else { stepI--; } } result++; } stepCount = 0; while ((result + deviation) * (result + deviation) < source ) { count++; stepCount++; if(stepCount%3==0){ //加快結果累計,調整步長 if((result + stepD) * (result + stepD) < source) { result += stepD; stepD+=deviation; continue; } else { stepD-=deviation; } } result += deviation; } System.out.println("sqrt1 total count :" + count); return result; }本算法每當執行循環三次時調整一次步長,讀者可以自行定制更加高效的調整步長策略。
算法三(二分法):
/** * 求開方 優化,二分法 * 該方法效率明顯比前兩個方法快的多 * @param source 被開方數,大于等于0 * @param deviation 誤差范圍 * @return */ public static double sqrt2(double source,double deviation) { if(source < 0 || deviation <0) { throw new RuntimeException("don't transmit negtive"); } long count = 1;//統計循環執行次數 double result = 0; double head = source; double tail = 0; while(true) { count++; if(((head+tail)/2) * ((head+tail)/2) < source) { tail = (head+tail)/2; } else { head = (head+tail)/2; } result = (head+tail)/2; if((result + deviation)*(result + deviation) >= source && (result - deviation)*(result - deviation) <= source) { break; } } System.out.println("sqrt2 total count:" + count); return result; }本算法為典型的二分法,算法的原理如下:將0和source分別作為結果的初始下界和上界,將下界和上界的平均值與真實結果比較并調整結果的下界或者上界,直至結果位于真實結果的誤差范圍內。
上面已經給出了算法的實現,算法可能的難點是怎么判斷算出的值是否在誤差范圍內,讀者需要注意這點。下面通過幾組數據簡單的比較一下不同算法實現之間的效率差別:
上圖中,我們測試了三組數據,從標紅的數據可以看出,算法二明顯優于算法一,而算法三明顯優于算法二。當執行第三組數據時,算法一甚至要等一小會兒才能執行完,而算法三卻馬上就能得到結果,而且算法三隨著問題規模的擴大執行次數卻增長很慢,而這只是簡單的幾行代碼改進的結果。從這個算法問題中我們可以看到不同算法之間效率的巨大差距,由此不難體會在許多算法應用場合下算法巨大的威力。
新聞熱點
疑難解答