最近在看《算法導論》這本書,在它的第二章出現了一個很是有意思的概念——循環不變式(Loop Invariant)。一言以蔽之,提出循環不變式的目的是爲了從理論上證實某個算法是正確的。算法
說實話我之前沒有思考過這個問題。習慣養成的緣由,我在調試代碼時,老是試各類各樣的輸入和查看對應的輸出以保證整個程序是正確的。並非說這樣是錯誤的,而是指這個習慣讓我沒有去思考從理論上證實算法正確性這條路。若是隻是盲目地多試幾個輸入的話,就好像讓電腦用算術去證實哥德巴赫猜測同樣,是很是不優雅的。你能夠證實很是大的數知足哥德巴赫猜測,但你永遠也沒法說哥德巴赫猜測是對的。數組
其實從理論上證實算法的正確性簡單得使人驚訝,這個過程跟數學概括法一模一樣。 咱們先來看看數學概括法是怎樣的。oop
數學概括法有這麼兩步spa
咱們來舉個例子調試
等差數列求和公式如何進行求證呢?code
驗證該公式在
時成立。即有左邊
,右邊=
,因此這個公式在
時成立。排序
須要證實假設
時公式成立,那麼能夠推導出
時公式也成立。步驟以下:get
- 假設
時公式成立,即
(等式1)
- 而後在等式兩邊同時分別加上
獲得
(等式2) 這就是
時的等式。咱們下一步須要根據 等式1證實 等式2 成立。經過因式分解合併,等式2的右邊
也就是
這樣咱們就完成了由
成立推導出
成立的過程,證畢。數學
結論:對於任意天然數n,公式均成立。it
那麼接下來就讓咱們用相似於數學概括法證實公式的方法來證實循環不變式以證實算法的正確性。
咱們以插入排序爲例子(升序,在這裏用僞代碼來表示,數組的下標是):
INSERTION-SORT(A)
for j = 2 to A.length
key = A[j]
i = j-1
while i>0 and A[i] > key
A[i+1] = A[i]
i = i-1
A[i+1] = key
複製代碼
就好像這樣的公式同樣,在此咱們能夠爲插入排序提出一個循環不變式:在每次for循環迭代開始以前,子數組
仍是原來位置在
的元素而且已經排好序了。
那麼就跟數學概括法證實公式同樣,咱們須要兩步來證實它的正確性:
但由於咱們須要循環不變式來證實算法的正確性,咱們須要着重看循環結束時的狀況,那麼就引出了咱們須要證實循環不變式的第三個性質:
那麼讓咱們來看看是怎樣具體證實的:
你會發現利用循環不變式來證實算法的正確性是如此得簡單和優雅。