本文講述在編寫c
程式**的常用優化辦法,分為i/o
篇,記憶體篇,演算法篇,mmx
彙編篇。
二.記憶體篇
i.優化陣列的定址
在編寫程式時,我們常常使用乙個一維陣列a[m×n]來模擬二維陣列a[n][m],這個時候訪問a一維陣列的時候:我們經常是這樣寫a[j×m+i](對於a[j][i])。這樣寫當然是無可置疑的,但是顯然每個定址語句j×m+i都要進行一次乘法運算。現在再讓我們看看二維數值的定址,說到這裡我們不得不深入到c編譯器在申請二維陣列和一維陣列的內部細節上――實際在申請二位陣列和一維陣列,編譯器的處理是不一樣的,申請乙個a[n][m]的陣列要比申請乙個a[m×n]的陣列占用的空間大!二維陣列的結構是分為兩部分的:
① 是乙個指標陣列,儲存的是每一行的起始位址,這也就是為什麼在a[n][m]中,a[j]是乙個指標而不是a[j][0]資料的原因。
② 是真正的m×n的連續資料塊,這解釋了為什麼乙個二維陣列可以象一維陣列那樣定址的原因。(即a[j][i]等同於(a[0])[j×m+i])
清楚了這些,我們就可以知道二維陣列要比(模擬該二維陣列的)一維陣列定址效率高。因為a[j][i]的定址僅僅是訪問指標陣列得到j行的位址,然後再+i,是沒有乘法運算的!
所以,在處理一維陣列的時候,我們常常採用下面的優化辦法:(偽碼例子)
int a[m*n];
int *b=a;
for(…)
這個是遍歷訪問陣列的乙個優化例子,每次b+=m就使得b更新為下一行的頭指標。當然如果你願意的話,可以自己定義乙個陣列指標來儲存每一行的起始位址。然後按照二維陣列的定址辦法來處理一維陣列。不過,在這裡我建議你乾脆就直接申請乙個二維陣列比較的好。下面是動態申請和釋放乙個二維陣列的c**。
int get_mem2dint(int ***array2d, int rows, int columns) 源**
void free_mem2d(byte **array2d)
else}
順便說一下,如果你的陣列定址有乙個偏移量的話,不要寫為a[x+offset],而應該為 b=a+offset,然後訪問b[x]。
不過,如果你不是處理對速度有特別要求的程式的話,這樣的優化也就不必要了。記住,如果編普通程式的話,可讀性和可移值性是第一位的。
ii.從負數開始的陣列
在程式設計的時候,你是不是經常要處理邊界問題呢?在處理邊界問題的時候,經常下標是從負數開始的,通常我們的處理是將邊界處理分離出來,單獨用額外的**寫。那麼當你知道如何使用從負數開始的陣列的時候,邊界處理就方便多了。下面是靜態使用乙個從-1開始的陣列:
int a[m];
int *pa=a+1;
現在如果你使用pa訪問a的時候就是從-1到m-2了,就是這麼簡單。(如果你動態申請a的話,free(a)可不要free(pa)因為pa不是陣列的頭位址)
iii.我們需要鍊錶嗎
相信大家在學習《資料結構》的時候,對鍊錶是相當熟悉了,所以我看有人在編寫一些耗時演算法的時候,也採用了鍊錶的形式。這樣編寫當然對記憶體的占用(似乎)少了,可是速度呢?如果你測試:申請並遍歷10000個元素鍊錶的時間與遍歷相同元素的陣列的時間,你就會發現時間相差了百倍!(以前測試過乙個演算法,用鍊錶是1分鐘,用陣列是4秒鐘)。所以這裡我的建議是:在編寫耗時大的**時,盡可能不要採用鍊錶!
其實實際上採用鍊錶並不能真正節省記憶體,在編寫很多演算法的時候,我們是知道要占用多少記憶體的(至少也知道個大概),那麼與其用鍊錶一點點的消耗記憶體,不如用陣列一步就把記憶體占用。採用鍊錶的形式一定是在元素比較少,或者該部分基本不耗時的情況下。
(我估計鍊錶主要慢是慢在它是一步步申請記憶體的,如果能夠象陣列一樣分配乙個大記憶體塊的話,應該也不怎麼耗時,這個沒有具體測試過。僅僅是猜想 :p)
Android效能優化之路(二)
上次講到了什麼是android裝置的卡頓以及定位卡頓的原因的工具。這次來看看與螢幕繪製相關。gpu過度繪製 overdraw 是什麼?overdraw是指在一幀的時間內 1 60s 畫素被繪製了多次。理論上的最優是只繪製一次,但是重疊的布局會導致某些畫素被繪製多次,當繪製畫素的時常超過1 60s時,...
C 優化程式
1 自定義程式的入口 2 合併區段 3 不用調malloc,free等函式 3 不用cout來輸出,cin來輸入 4 如果呼叫了很多庫函式如memset,stycpy等等 的話,請匯入msvcrt.lib,不然編譯器會在程式裡面 匯入靜態庫,這樣的話程式就會大很多。5 window 程式設計不用mf...
C程式優化
1 在做任何執行速度上的優化時,須充分考慮優化後 體積開銷缺陷 2 提倡使用查表方法 3 求餘,除法,乘法盡量採用位運算代替 4 平方運算,改為乘法運算 5 迴圈判斷條件盡量簡單明瞭 6 使用 do while 迴圈替代for and while迴圈 7 迴圈展開,可手動迴圈展開,也可由編譯器完成,...