程式設計珠璣 學習筆記3 效能

2021-06-23 02:25:41 字數 4505 閱讀 8048

軟體開發使用技術

1)構建指令碼架,也就相當於寫出測試用例

2)編碼——用高階偽**描繪出框架

3)測試——用第一步中的測試用例進行測試

4)除錯

5)計時

效能

1. 提公升程式執行速度

提公升程式執行速度的常用方法:從設計層次著手。

1)問題定義

2)系統結構

將大系統分解為模組,進行「封底」估計,以確保其效能近乎符合要求。

3)演算法和資料結構

4)**優化

比如可以用單精度浮點數運算來代替雙精度浮點數運算以加倍執行速度;可以將關鍵模組**直接用組合語言進行編寫來提高執行速度。

5)系統軟體

選用更高效的軟體來替代低效的軟體,比如對於查詢操作而言,新資料庫系統速度是否更快?

6)硬體

用執行速度更快的硬體。

具體實現方法:

eg.順序查詢

int  search1(int t)

for i = [0,n)

if x[i] == t

return i;

else 

return -1;

展開:int ssearch2(int t)

x[n] = t;

for (i =0;  ;i +=8)

if (x[i    ] == t)

if (x[i+1] == t)

if (x[i+2] == t)

if (x[i+3] == t)

if (x[i+4] == t)

if (x[i+5] == t)

if (x[i+6] == t)

if (x[i+7] == t)

if (i == n)

return -1

else 

return i

eg.求餘運算 %

源**:

k = (j+rotdist) % n 

修改為:

k = j + rotdist;

if (k> = n)

k -= n;

eg.二分查詢

初始:l = 0; u = n-1;

loop

if l > u 

p = -1;break;

m = (l+u) / 2

case

x[m] < t: l = m+1;

x[m] == t: p = m;break;

x[m] > t: u = m-1;

修改為:

l = -1; u = n; 

while(l+1 != u)

m = (l+u) / 2

if x[m] < t

l = m

else 

u = m

p = u;

if p>=n || x[p] != t

p = -1

當然還可以進行迴圈展開減少或者消除迴圈開銷,也還可以利用代數恒等式將上下限的表示方法更改為下限和增量表示法。

2. 壓縮空間

1)減少資料空間

2)減少**空間

——eg. 有的圖形處理程式具有整頁整頁類似下面所示的**:

for  i = [17,43]  set(i, 68)

for  i = [18,42]  set(i, 69)

for  j = [81,91]  set(30, j)

for j = [82,92]  set(31, j)

這裡,set(i, j)開啟螢幕位置(i, j)處的元素,使用合適的函式,比如繪製水平線和垂直線的hor和ver函式,可以如下所示替換那段**:

hor(17, 43, 68)

hor(18, 42, 69)

vert(81, 91, 30)

vert(82, 92, 31)

上述**又可以用乙個直譯器來替換,這個直譯器從類似下面的陣列中讀取命令:

h   17   43   68

h   18   42   69 

v    81   91   30

v    82   92   31

3) 重寫原則——簡單性

3. 封底計算

「任何事情應該做到盡可能的簡單,除非沒有更簡單的了」——愛恩斯坦。

「利特爾法則」——系統中物體的平均數量就是系統中物體離開系統的平均速率和每個物體在系統中停留的平均時間的乘積。比如某個酒徒在自己的存有150個盛滿酒的容器,他每年會喝完(和買回)25個容器的酒,問每個容器要保留多少年?(結果是:150/25=6年)

封底計算也就是對軟體執行時間進行估計,安全係數的引入可以彌補估計引數時可能的錯誤以及對手邊問題的無知帶來的意外情況。因此,在進行可靠性/可用性承諾時,應該對我們能滿足的目標保留乙個10的係數,以補償未知情況;在估計規模、成本以及進度時,我們應該保留2或者4的係數,以彌補在某些方面設計上的缺陷。

著名名詞:"back of the envelope"、"fermi problem"。

通過演算法減少程式執行時間示例:求輸入向量中任何相鄰子向量中的最大和,模型為一維模式識別。

輸入:乙個具有n個浮點數的向量 x;

輸出:x 中任何子向量的最大和。(當所有輸入都是負數時,最大子向量為空,其和為0)

eg. 

輸入:31  -41  59  26  -53  58  97  -93  -23  84

輸出:x[2...6]子向量的和187

1)最簡單的演算法——迭代所有情形(時間複雜度 o(n^3))

maxsofar = 0

for i = [0,n)

for j = [i,n)

sum = 0

for k =[i,j]

sum += x[k]     //sum of x[i...j]

maxsofar = max(sum, maxsofar)

2)利用前一步的結果(時間複雜度o(n^2))

maxsofar = 0;

for i = [0,n)

sum = 0;

for j = [i,n)

sum += x[j];   //sum of x[i...j]

maxsofar = max(sum, maxsofar);

3)分治演算法(時間複雜度o(n*logn))

思想:將原始序列分解成左右兩部分,則最大子向量和有3種情況:在左邊部分;在右邊部分;由兩者合成。

float maxsum(l,u)

if (l>u)   //zero element

return 0;

if(l==u)  //one element

return max(x[l],0)

m = (l+u)/2;

lmax=0;rmax=0;

lsum=0;rsum=0

for(i=m; i>=l; i--)

lsum += x[i];

lmax = max(lsum, lmax);

for i=(m,u]

rsum += x[i];

rmax = max(rsum,rmax);

return max(maxsum(l,m),maxsum(m+1,u),lmax+rmax);  //recursion

最初呼叫方式:float res = maxsum(0,n-1)。

4)掃瞄演算法(時間複雜度o(n),為線性演算法)

思想:從左端開始,一直掃瞄到最右端,記下碰到過的最大總和子向量。

maxsofar = 0;

maxendinghere = 0;

for i = [0,n)

maxendinghere = max(maxendinghere + x[i], 0);

maxsofar = max(maxendinghere,maxsofar);

eg.x: 31  -41  59  26  -53  58  97  -93  -23  84

i=0: maxendinghere = 31;  maxsofar = 31.

i=1: maxendinghere = 0;  maxsofar = 31.

i=2: maxendinghere = 49;  maxsofar = 49.

i=3: maxendinghere = 75;  maxsofar = 75.

i=4: maxendinghere = 22;  maxsofar = 75.

i=5: maxendinghere = 80;  maxsofar = 80.

i=6: maxendinghere = 187;  maxsofar = 187.

i=7: maxendinghere = 94;  maxsofar = 187.

i=8: maxendinghere = 71;  maxsofar = 187.

i=9: maxendinghere = 155;  maxsofar = 187.

所以,最終結果為187.

《程式設計珠璣》看書筆記

臨睡前翻看了下 程式設計珠璣 續 這本書,看到第一章就被吸引了,效能監視工具這節從計算素數入手。題目是 列印所有小於1000的素數 簡單直白的方法就是,針對每個小於1000的數字n,從2開始到n 1,如果能被任意乙個數整除,那它就不是素數。如下 int prime int n return 1 in...

程式設計珠璣筆記1

乙個檔案裡有1千萬 10000000 個7位的整數 小於1千萬 給大約1m記憶體讓排序 向量旋轉 abcdefgh 長度n為8 向左旋轉i 3次 某檔案包含40億個隨機次序32位整數,其中有乙個整數未出現,找出來。限制 記憶體幾百位元組,若干順序檔案。乙個詞典有230000個單詞,file和life...

讀《程式設計珠璣》筆記

程式設計珠璣 是一本很好的,經典的程式設計書。這兩天開始讀,有種 相見恨晚 的感覺。書中通過講述作者自己的親身體會來說明程式設計的藝術。很有感染力。第一章講述了乙個 號碼排序的故事。強調化蘩為簡的重要性。很多問題,咋一看挺難的,如果仔細分析轉化,可能會發現其實很簡單。第二章二分搜尋和排序在實際問題處...