關於判斷素數的幾點
//該函式有嚴重缺點:
//不能用於n==1和n較大的情況
//在n接近int的最大值時:
//若i=46340時,i*i=2147395600//若i=46341時,i*i=2147488281超過了int的最大值,溢位變成了負數,就會繼續進行下去
intis_prime
(int n)
return1;
}//編寫函式的時候,應該盡量保證該函式能對任何合法引數得到正確的結果
//改進後
//優點:避免了每次重複計算sqrt(n)
//通過四捨五入避免了浮點誤差
intis_prime
(int n)
return1;
}
謹慎地使用全域性變數呼叫棧描述的是函式之間的呼叫關係
由多個棧幀組成,每個棧幀對應著乙個未執行完的函式
棧幀中儲存了該函式的返回位址和區域性變數,因而不僅能在執行完畢後找到正確的返回位址,還能自然地保證了不同函式間的區域性變數互不相干——因為不同函式之間對應不同的棧幀
這有一段錯誤的程式
void
swap
(int
* a,
int* b)
這個程式錯誤的原因是:
指標 t 在使用之前必須賦值
t在賦值之前是不確定的。如果這個不確定的值所代表的記憶體單元恰好是能寫入的,那麼這段程式將正常工作;但如果不是,而是唯讀的,那麼程式就會可能崩潰
這有一段錯誤的程式:
int
sum(
int a)
return ans;
}
錯誤的原因:一般的,若p是指標,k是正整數,那麼p+k就是指標p後面的第k個元素,p-k是p前面的第k個元素,而如果p1和p2是型別相同的指標,則p2-p1是從p1到p2的元素個數sizeof(a)是無法得到陣列的大小的
因為,陣列作為引數傳遞給函式時,實際上只有陣列的首位址作為指標傳遞給了函式。
在函式定義中的int a等價於int *a。
在只有位址資訊的情況下,是無法知道陣列裡有多少個元素的
正確的做法:
加乙個引數,即陣列的元素個數
那麼我們對計算陣列和的函式可以用兩種寫法:
1.
int
sum(
int* begin,
int* end)
return ans;
}
int
sum(
int* begin,
int* end)
return ans;
}
上述兩種寫法都是左閉右開
第二種寫法更為普遍
把陣列作為指標傳遞給函式時,陣列內容是可以修改的。
如果要寫乙個「返回陣列「的函式,可以加乙個陣列引數,然後在函式中修改這個陣列的內容
在c語言的函式中,呼叫自己和呼叫其他函式並沒有任何本質區別,都是建立新棧幀,傳遞引數並修改當前**行。
在函式體執行完畢後,刪除棧幀,處理返回值並修改當前**行。
編譯後產生的可執行檔案裡都儲存著與作業系統相關的內容。
段。是指二進位制檔案內的區域,所有某種特定型別的資訊被儲存在裡面。
在可執行檔案裡,正文段用於儲存指令
資料段用於儲存已初始化的全域性變數
bss段用於儲存未賦值的全域性變數所需的空間
呼叫棧不儲存在可執行檔案中,而是在執行時建立
呼叫棧所在段稱為堆疊段
堆疊段也有自己的大小,不能被越界訪問,否則就會出現段錯誤
棧溢位,那麼就是每次遞迴呼叫都會往呼叫棧裡增加乙個棧幀,久而久之,就越界了。
在執行時,程式會動態建立乙個堆疊段,裡面存放著呼叫棧,因此儲存著函式的呼叫關係和區域性變數
區域性變數也是存放在堆疊段內的。
棧溢位不一定是遞迴呼叫太多,也可能是區域性變數太大
因此,我們一般把較大的陣列存放在main函式外
例題4-1 古老的密碼 uva1339
//qsort函式的宣告
void
qsort
(void
* base, size_t num, size_t size,
int(
*comparator)
(const
void*,
const
void*)
)//qsort函式實現的是快速排序演算法
//引數說明:
//待排序的陣列起始位址
//元素個數
//元素的大小
//乙個指向函式的指標,該函式必須具有以下行書
intcmp
(const
void*,
const
void*)
//這個函式中,const void *的意思是:
//指向常數的萬能的指標,它可以通過強制型別轉化變成任意型別的指標
//例如,如果排序的物件是個整型陣列,那麼:
intcmp
(const
void
* a,
const
void
* b)
//一般的,需要先把引數a和引數b轉化為真實的型別,然後讓cmp函式當ab時分別返回負數,0,和正數即可。
qsort在演算法競賽中不經常使用
經常使用sort函式
這裡是為了告訴「將乙個函式作為引數傳遞給另外乙個函式」是很有用的
例題4-2 劊子手遊戲 uva489
我們先來考慮,程式設計的方式
一般有兩種:
自頂向下和自底向上
演算法競賽中一般是自頂向下
即:先寫偽**,然後轉化為實際的**
先寫主程式,包括對函式的呼叫,在實現函式本身。
這個題沒有什麼難點,只是說注意一點就可以
**的注釋我都不想寫了
太簡單了
#include
#include
#define maxn 100
int left, chance;
char s[maxn]
, s2[maxn]
;int win, lose;
void
guess
(char ch)}if
(bad)
--chance;if(
!chance)
lose =1;
if(!left)
win =1;
}int
main()
if(win)
printf
("you win.\n");
else
if(lose)
printf
("you lose.\n");
else
printf
("you chickened out.\n");
}return0;
}
例題4-3 救濟金發放 uva133
這個需要注意的地方就是
迴圈的處理方式
這個算作是約瑟夫環的高階版
intgo(
int p,
int d,
int t)
while
(a[p]==0
);//跳過為0項
}return p;
}
例題4-4 資訊解碼 uva213
書上**:
#include
#include
intreadchar()
}//readint主要用於讀取01序列
intreadint
(int c)
//用於讀取c位二進位制字元,並轉換為十進位制數
return v;
}int code[8]
[1<<8]
;int
readcodes()
//用於讀取編碼,並形成編碼序列
}return1;
}int
main()
}putchar
('\n');
}return0;
}
習題4-1 uva1589
習題4-2 uva201
習題4-3 uva220
習題4-4 uva253
習題4-5 uva1590
習題4-6 uva508
習題4-7 uva509
習題4-8 uva12108
習題4-9 uva1591
習題4-10 uva815
習題4-11 uva1588
習題4-12 uva11809
《演算法競賽入門經典》第四章小結
題目 編寫乙個函式solve,給定浮點數a,b,c,d,e,f,求解方程組ax by c,dx ey f.任務1 使用assert巨集,讓解不唯一時異常退出。任務2 解不唯一時仍正常返回,但呼叫者有辦法知道解的數量 無解,唯一解,無窮多組解 思考 函式的引數都有哪些,各是什麼型別?任務1 inclu...
演算法競賽入門經典 第四章答案
4.4.1 小問題集錦 任務1 使用assert巨集,讓解不唯一時退出。include includevoid solve double a,double b,double c,double d,double e,double f,double x,double y int main 任務2 解不唯...
演算法競賽入門經典第四章習題
習題4 1 題目大意就是 乙個象棋殘局,紅方有n 2 n 7 個棋子,黑方只有乙個將,紅方除了帥,還可能有車,馬,炮,並且要考慮 蹩馬腿 輸入所有棋子的位置,保證局面合法並且紅方已經將軍,判斷紅方是否已經將黑方將死,解題思路 用乙個棋盤儲存紅方可以打到的地方,看黑方將是否有其餘的地方去,在豎直方向只...