《演算法基礎 開啟演算法之門》一2 3 迴圈不變式

2021-09-23 15:09:00 字數 1290 閱讀 9939

對於線性查詢的3個演算法,我們能很容易地看到每個演算法均能生成正確的結果。但是有時候生成正確的結果看起來有點難。這涉及一系列技術,在這裡不能一一講解。

證明正確性的乙個常用方法是使用迴圈不變式證明:即證明迴圈的每次迭代之前迴圈不變式為真。迴圈不變式能夠幫助我們證明正確性,關於迴圈不變式,我們必須證明以下3條性質。

初始化:迴圈的第一次迭代之前,它為真。

保持:如果迴圈的每次迭代之前它為真,那麼下次迭代之前它仍為真。

終止:迴圈終止時,當它確實終止時,伴隨迴圈終止的原因,迴圈不變式為我們提供了乙個有用的性質。以betterlinearsearch演算法為例,以下是乙個迴圈不變式:

在第1步迭代開始時,如果陣列a中存在x,那麼x一定在a[i]~a[n]的子陣列(陣列的一段連續部分)中。我們甚至不需要迴圈不變式來證明如果程式返回了乙個索引而非notfound,則被返回的索引是正確的:在第1a步中該程式能返回索引i的唯一方式是因為x等於a[i]。下面,我們使用迴圈不變式來證明如果程式是在第2步中返回notfound,那麼陣列中一定不包含x。初始化:初始時,i=1,因此迴圈不變式的子陣列是a[1]~a[n],此時代表整個陣列。保持:假定當前迴圈變數是i,在迭代開始時,如果陣列a中包含x,那麼它一定在從a[i]到a[n]的子陣列中。如果執行這次迴圈迭代而沒有返回值,我們能得出a[i]≠x,因此能確定地說如果x在陣列a內,那麼它一定出現在a[i+1]~a[n]的子陣列內。因為i在下次迭代之前會自增1,21所以迴圈不變式在下次迭代之前仍為真。終止:迴圈一定會終止,或者因為程式會在第1a步返回,或者由於i>n。我們已經對程式因在第1a步返回而導致迴圈終止的情況進行了驗證。為了處理因i>n而導致迴圈終止的情況,我們依據迴圈不變式的等價性來證明。命題「如果a那麼b」的逆否命題是「如果非b那麼非a」。乙個命題為真當且僅當與它等價的命題也為真。該迴圈不變式的等價命題為「如果x沒有出現在a[i]~a[n]的子陣列中,那麼陣列a中就不存在x」。現在,當i>n時,a[i]~a[n]這個子陣列為空。因此這個子陣列中不可能包含x。因此,根據迴圈不變式的等價式,x不可能出現在陣列a的任意位置上,因此第2步中返回notfound是恰當的。這一系列的推理僅僅是為了說明這麼乙個簡單的迴圈?每次寫乙個迴圈時,我們都必須新增上述證明嗎?我不會,但是針對每乙個簡單的迴圈,依舊有幾個計算機科學家堅持這樣嚴格的推理。在實際程式設計時,我發現在我寫乙個迴圈的大部分時間裡,我會在頭腦裡想出迴圈不變式。它可能深藏在我的頭腦中以至於我甚至沒有意識到我的大腦裡會存在該迴圈不變式,但是如果要求我必須陳述該迴圈不變式,我能夠完整地將其表述下來。雖然我們中的大多數人認為迴圈不變式對於理解像betterlinearsearch這樣的簡單迴圈沒有必要,但是我們想要理解複雜的迴圈能夠執行正確的操作時使用迴圈不變式會很方便。

《演算法基礎 開啟演算法之門》一2 4 遞迴

利用遞迴技術,能將乙個問題轉化為同乙個樣子問題的求解過程。這是我最喜歡的經典的遞迴例子 計算n n的階乘 它被定義為如下,對於乙個非負數n,當n 0時,n 1且n n n 1 n 2 n 3 3 2 1 如果n 1 例如,5 5 4 3 2 1 120。22觀察得 n 1 n 1 n 2 n 3 3...

《演算法基礎 開啟演算法之門》一3 2 選擇排序

現在讓我們將注意力轉向排序 重排陣列中的所有元素 也稱為重排陣列 以便每個元素小於或者等於它的後繼。我們要看到的第一種排序演算法是選擇排序,這是我能想到的最簡單的演算法,在設計乙個排序演算法時,我最先能想到的就是選擇排序,雖然它遠遠不是最快的演算法。下面我們用依據作者名字對書架上的書排序這個例子來說...

23 迴圈巢狀中演算法優化

100000以內的所有質數的輸出 體會演算法的優化一 public class primenumber1 if fag fag true system.out.println 質數個數為 even long end system.currenttimemillis system.out.printl...