嵌套For循環性能優化

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。
1 案例描述
某日,在JavaEye上看到一道面試題,題目是這樣的:請對以下的代碼進行優化
Java代碼 復制代碼?收藏代碼
  1. for?(int?i?=?0;?i?<?1000;?i++)??
  2. ????for?(int?j?=?0;?j?<?100;?j++)??
  3. ????????for?(int?k?=?0;?k?<?10;?k++)??
  4. ????????????testFunction?(i,?j,?k);??
for (int i = 0; i < 1000; i++)for (int j = 0; j < 100; j++)for (int k = 0; k < 10; k++)testFunction (i, j, k);

(注:為了同后面的內容一致,這里對原題目進行了部分修改)

2 案例分析
從給出的代碼可知,不論如何優化,testFunction執行的次數都是相同的,該部分不存在優化的可能。那么,代碼的優化只能從循環變量i、j、k的實例化、初始化、比較、自增等方面的耗時上進行分析。
首先,我們先分析原題代碼循環變量在實例化、初始化、比較、自增等方面的耗時情況:
變量實例化(次數)初始化(次數)比較(次數)自增(次數)
i1110001000
j100010001000 * 1001000 * 100
k1000 * 1001000 * 1001000 * 100 * 101000 * 100 * 10

(注:由于單次耗時視不同機器配置而不同,上表相關耗時采用處理的次數進行說明)
該代碼的性能優化就是盡可能減少循環變量i、j、k的實例化、初始化、比較、自增的次數,同時,不能引進其它可能的運算耗時。

3 解決過程
從案例分析,對于原題代碼,我們提出有兩種優化方案:
3.1 優化方案一
代碼如下:
Java代碼 復制代碼?收藏代碼
  1. for?(int?i?=?0;?i?<?10;?i++)??
  2. ????for?(int?j?=?0;?j?<?100;?j++)??
  3. ????????for?(int?k?=?0;?k?<?1000;?k++)??
  4. ????????????testFunction?(k,?j,?i);??
for (int i = 0; i < 10; i++)for (int j = 0; j < 100; j++)for (int k = 0; k < 1000; k++)testFunction (k, j, i);

該方案主要是將循環次數最少的放到外面,循環次數最多的放里面,這樣可以最大程度的(注:3個不同次數的循環變量共有6種排列組合情況,此種組合為最優)減少相關循環變量的實例化次數、初始化次數、比較次數、自增次數,方案耗時情況如下:
變量實例化(次數)初始化(次數)比較(次數)自增(次數)
i111010
j101010 * 10010 * 100
k10 * 10010 * 10010 * 100 * 100010 * 100 * 1000


3.2 優化方案二
代碼如下:
Java代碼 復制代碼?收藏代碼
  1. int?i,?j,?k;??
  2. for?(i?=?0;?i?<?10;?i++)??
  3. ????for?(j?=?0;?j?<?100;?j++)??
  4. ????????for?(k?=?0;?k?<?1000;?k++)??
  5. ????????????testFunction?(k,?j,?i);??
int i, j, k;
for (i = 0; i < 10; i++)for (j = 0; j < 100; j++)for (k = 0; k < 1000; k++)testFunction (k, j, i);

該方案在方案一的基礎上,將循環變量的實例化放到循環外,這樣可以進一步減少相關循環變量的實例化次數,方案耗時情況如下:
變量實例化(次數)初始化(次數)比較(次數)自增(次數)
i111010
j11010 * 10010 * 100
k110 * 10010 * 100 * 100010 * 100 * 1000


4 解決結果
那么,提出的優化方案是否如我們分析的那樣有了性能上的提升了呢?我們編寫一些測試代碼進行驗證,數據更能說明我們的優化效果。
4.1 測試代碼
Java代碼 復制代碼?收藏代碼
  1. public?static?void?testFunction(int?i,?int?j,?int?k)?{??
  2. ????????System.out.print("");???//?注:該方法不影響整體優化,這里只有簡單輸出??
  3. ????}??
  4. ??
  5. ????public?static?void?testA()?{??
  6. ????????long?start?=?System.nanoTime();??
  7. ????????for?(int?i?=?0;?i?<?1000;?i++)??
  8. ????????????for?(int?j?=?0;?j?<?100;?j++)??
  9. ????????????????for?(int?k?=?0;?k?<?10;?k++)??
  10. ????????????????????testFunction(i,?j,?k);??
  11. ????????System.out.println("testA?time>>"?+?(System.nanoTime()?-?start));??
  12. ????}??
  13. ??
  14. ????public?static?void?testB()?{??
  15. ????????long?start?=?System.nanoTime();??
  16. ????????for?(int?i?=?0;?i?<?10;?i++)??
  17. ????????????for?(int?j?=?0;?j?<?100;?j++)??
  18. ????????????????for?(int?k?=?0;?k?<?1000;?k++)??
  19. ????????????????????testFunction(k,?j,?i);??
  20. ????????System.out.println("testB?time>>"?+?(System.nanoTime()?-?start));??
  21. ????}??
  22. ??
  23. ????public?static?void?testC()?{??
  24. ????????long?start?=?System.nanoTime();??
  25. ????????int?i;??
  26. ????????int?j;??
  27. ????????int?k;??
  28. ????????for?(i?=?0;?i?<?10;?i++)??
  29. ????????????for?(j?=?0;?j?<?100;?j++)??
  30. ????????????????for?(k?=?0;?k?<?1000;?k++)??
  31. ????????????????????testFunction(k,?j,?i);??
  32. ????????System.out.println("testC?time>>"?+?(System.nanoTime()?-?start));??
  33. }??
public static void testFunction(int i, int j, int k) {System.out.print("");	// 注:該方法不影響整體優化,這里只有簡單輸出}public static void testA() {long start = System.nanoTime();for (int i = 0; i < 1000; i++)for (int j = 0; j < 100; j++)for (int k = 0; k < 10; k++)testFunction(i, j, k);System.out.println("testA time>>" + (System.nanoTime() - start));}public static void testB() {long start = System.nanoTime();for (int i = 0; i < 10; i++)for (int j = 0; j < 100; j++)for (int k = 0; k < 1000; k++)testFunction(k, j, i);System.out.println("testB time>>" + (System.nanoTime() - start));}public static void testC() {long start = System.nanoTime();int i;int j;int k;for (i = 0; i < 10; i++)for (j = 0; j < 100; j++)for (k = 0; k < 1000; k++)testFunction(k, j, i);System.out.println("testC time>>" + (System.nanoTime() - start));
}

4.2 測試結果
1、測試機器配置:Pentium(R) Dual-Core CPU E5400 @2.70GHz 2.70GHz, 2GB內存;
2、循環變量i、j、k循環次數分別為10、100、1000,進行5組測試,測試結果如下:
?第1組第2組第3組第4組第5組
原方案171846271173250166173910870173199875173725328
方案一168839312168466660168372616168310190168041251
方案二168001838169141906168230655169421766168240748

從上面的測試結果來看,優化后的方案明顯性能優于原方案,達到了優化的效果。但優化方案二并沒有如我們預期的優于方案一,其中第2、4、5組的數據更是比方案一差,懷疑可能是循環次數太少,以及測試環境相關因素影響下出現的結果。

3、重新調整循環變量i、j、k循環次數分別為20、200、2000,進行5組測試,測試結果如下:
?第1組第2組第3組第4組第5組
原方案13553972031358978176135812828113501936821354786598
方案一13434827041348410388134397803713479191561340697793
方案二13424275281343897887134266246213421240481336266453

從上面的測試結果來看,優化后的方案基本符合我們的預期結果。

5 總結
從案例分析和解決過程中的三個表的分析可知,優化方案一和優化方案二的性能都比原代碼的性能好,其中優化方案二的性能是最好的。在嵌套For循環中,將循環次數多的循環放在內側,循環次數少的循環放在外側,其性能會提高;減少循環變量的實例化,其性能也會提高。從測試數據可知,對于兩種優化方案,如果在循環次數較少的情況下,其運行效果區別不大;但在循環次數較多的情況下,其效果就比較明顯了。

6 參考資料
[1] http://www.javaeye.com/topic/762312
[2] http://www.javaeye.com/topic/632481

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/452271.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/452271.shtml
英文地址,請注明出處:http://en.pswp.cn/news/452271.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

docker-ce安裝

1、安裝 sudo yum -y install docker 2、加入開機自啟systemctl enable docker轉載于:https://www.cnblogs.com/runnerjack/p/8618524.html

python-study-17

復習 上節課復習1、什么是模塊模塊是一系列功能的集合體2、為何用模塊拿來&#xff08;內置或第三方的模塊&#xff09;主義&#xff0c;提升開發效率自定義模塊可以讓程序的各部分組件重用模塊內的功能3、如何用模塊大前提&#xff1a;模塊是被執行文件導入使用&#xff0c;模…

面向對象方法學的優點

1.與人類習慣的思維方法一致面向對象的軟件技術以對象為核心&#xff0c;用這種技術開發出的軟件系統由對象組成。對象是由描述內部狀態表示靜態屬性的數據&#xff0c;以及可以對這些數據施加的操作(對象的動態行為)&#xff0c;封裝在一起所構成的統一體。面向對象的設計方法…

如何學好C語言

我相信&#xff0c;這可能是很多朋友的問題&#xff0c;我以前也有這樣的感覺&#xff0c;編程編到一定的時候&#xff0c;發現能力到了瓶頸&#xff0c;既不深&#xff0c;也不扎實&#xff0c;半吊子。比如&#xff1a;你長期地使用Java和.NET &#xff0c;這些有虛擬機的語言…

學成在線--5.CMS頁面管理開發(修改頁面)

文章目錄1.修改頁面流程1&#xff09;前端邏輯2&#xff09;后端邏輯2.修改頁面接口定義3.后端開發--Dao4.后端開發--Service5.后端開發--Controller1&#xff09;根據id查詢頁面2&#xff09;保存頁面信息6.前端開發--頁面處理流程7.前端開發--編寫page_edit.vue8.前端開發--配…

在樹莓派上播放音頻

https://blog.csdn.net/qinxiandiqi/article/details/39155593轉載于:https://www.cnblogs.com/Baronboy/p/9206164.html

Map四種獲取key和value值的方法,以及對map中的元素排序

2019獨角獸企業重金招聘Python工程師標準>>> 獲取map的值主要有四種方法&#xff0c;這四種方法又分為兩類: 一類是調用map.keySet()方法來獲取key和value的值&#xff0c; 另一類則是通過map.entrySet()方法來取值&#xff0c; 兩者的區別在于&#xff0c;前者主要…

配置Oracle Instant Client環境

1.配置Oracle Instant Client環境 到Oracle官網下載Oracle Instant Client&#xff0c;注意選擇x86平臺&#xff0c;Toad只認32位的Oracle Instant Client。至于版本號&#xff0c;沒有特別要求&#xff0c;版本向下兼容。 桌面上&#xff0c;右鍵點“我的電腦”&#xff0c;選…

學成在線--6.CMS頁面管理開發(刪除頁面)

文章目錄0.刪除用戶邏輯1.刪除頁面接口定義2.后端開發--Dao3.后端開發--Service4.后端開發--controller5.前端開發--page_list.vue添加刪除按鈕6.前端開發--page_list.vue編寫刪除事件7.后端開發--Api方法定義Api方法0.刪除用戶邏輯 1&#xff09;前端邏輯 &#xff08;1&…

諾基亞是“不跟隨”還是跟不上?

在Android和iPhone為主流的環境下&#xff0c;諾基亞用“不跟隨”的口號表明自己欲保持個性&#xff0c;但是否也意味著其固步自封&#xff0c;跟不上時代&#xff1f; 5年市值縮水超900億歐元&#xff0c;全球業績連續4個季度虧損&#xff0c;更為可怕的是&#xff0c;被視為…

HTTP 協議(詳解)

HTTP協議簡介&#xff1a;HTTP協議是Hyper Text Transfer Protocol(超文本傳輸協議)的縮寫&#xff0c;是用于萬維網&#xff08;www.world wide web&#xff09;服務器與本地瀏覽器之間傳輸文本的傳輸協議。 http請求協議與相應協議HTTP協議包含瀏覽器發送數據到服務器需要遵循…

對象的特點

對象有如下一些基本特點。(1) 以數據為中心。操作圍繞對其數據所需要做的處理來設置&#xff0c;不設置與這些數據無關的操作&#xff0c;而且操作的結果往往與當時所處的狀態 (數據的值)有關。 (2) 對象是主動的。它是進行處理的主體。不能從外部直接加工它的私有數據&a…

React Native集成Redux框架講解與應用

學過React Native的都知道&#xff0c;RN的UI是根據相應組件的state進行render的&#xff0c;而頁面又是由大大小小的組件構成&#xff0c;導致每個組件都必須維護自身的一套狀態&#xff0c;因此當頁面復雜化的時候&#xff0c;管理state會相當吃力的。而redux提供了一套機制來…

【筆試記錄】2021/3/10阿里

阿里20210310春招筆試記錄-Python解題 第一題 問題描述&#xff1a; 小偷從出發點按指定方向出發&#xff0c;除非遇到墻或超出城市必須轉方向&#xff0c;不然只能直走。城市大小m*n。輸入描述&#xff1a; 1. 第1行&#xff0c;三個數字m n k&#xff1b;m*n表示城市大小&…

Spring mvc中@RequestMapping 6個基本用法小結

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 小結下spring mvc中的RequestMapping的用法。 1&#xff09;最基本的&#xff0c;方法級別上應用&#xff0c;例如&#xff1a; …

學成在線--7.CMS頁面管理開發(異常處理)

文章目錄1.異常處理的問題分析2.異常處理流程3.可預知異常處理1.自定義異常類2.異常拋出類3.異常捕獲類4.異常處理測試1&#xff09;定義錯誤代碼2&#xff09;異常處理測試4.不可預知異常處理1.定義異常捕獲方法1&#xff09;異常拋出測試2&#xff09;異常捕獲方法1.異常處理…

函數重載與運算符重載

有兩種重載&#xff1a;函數重載是指在同一作用域內的若干個參數特征不同的函數可以使用相同的函數名字&#xff1b;運算符重載是指同一個運算符可以施加于不同類型的操作數上面。就是對已有的運算符重新進行定義&#xff0c;賦予其另一種功能&#xff0c;以適應不同的數據類型…

Django(6)

為什么不用_set related_name和related_query_name的區別related_name將成為相關對象的屬性&#xff0c;允許您使用外鍵對模型進行“倒退”。例如&#xff0c;如果ModelA有像下面這樣的字段&#xff0c;那么model_b ForeignKeyField(ModelB, related_namemodel_as)這將使您能夠…

P5 RV1126編碼測試Demo

目錄 前言 01 測試Demo大致流程圖 02 代碼分析 2.1 VI設備初始化 2.2 使能通道 —— RK_MPI_VI_EnableChn 2.3 VI 和 VENC綁定 2.4 創建 編碼線程 前言 從本章開始我們將要學習嵌入式音視頻的學習了 &#xff0c;使用的瑞芯微的開發板 &#x1f3ac; 個人主頁&#xff1a…

MP算法和OMP算法及其思想

主要介紹MP(Matching Pursuits)算法和OMP(Orthogonal Matching Pursuit)算法[1]&#xff0c;這兩個算法雖然在90年代初就提出來了&#xff0c;但作為經典的算法&#xff0c;國內文獻(可能有我沒有搜索到)都僅描述了算法步驟和簡單的應用&#xff0c;并未對其進行詳盡的分析&…