SICP 習題 1 14 解題總結

2021-06-18 03:54:51 字數 4228 閱讀 7707

sicp 習題 1.14要求計算出過程count-change的增長階。count-change是書中1.2.2節講解的用於計算零錢找換方案的過程。

要解答習題1.14,首先你需要理解count-change的工作方式,要理解count-change的工作方式,最好是自己去實現一遍count-change。

為了避免自己直接抄書中的**,我決定自己實現一遍用來找換人民幣的的「count-change」。事實上,我在看完並理解count-change的**後,當我去實現人民幣版的「count-change」時,我就強制自己不再回去看「count-change」的**,保證自己有更多的主動思考。

有意思的是,當我實現完了回去看書上的**,發現兩者還是有挺大的區別,雖然演算法是一樣的,結果也都正確的。

首先我們得有個過程遍歷各種零錢,我為了簡化程式,只做了「元」的找換,「分」和「角」就略過了。

遍歷各種零錢的過程如下,就是遍歷「1元」,「2元」,「5元」,「10元」,「20元」,「50元」,「100元」這幾種零錢。

這裡就和書上有點差別,書上是記錄現在還可以使用幾種零錢,根據可以使用的零錢種類數量返回其中最大面值的金額。

我是簡單粗暴地從最小面值遍歷到最大面值。

(define (rmb-change-next-kind change-kind)

(cond ((= change-kind 1) 2)

((= change-kind 2) 5)

((= change-kind 5) 10)

((= change-kind 10) 20)

((= change-kind 20) 50)

((= change-kind 50) 100)

(else 0)))

書中講到的找換零錢的方法基於以下基本思路:

比如我們需要將100塊的人民幣找換成零錢,有幾種找換方式?可以簡單分為兩種:有使用1塊面額的,和沒有使用1塊面額的。

對於有使用1塊面額的,把這一塊錢去掉,剩99塊,我們又可以繼續看99塊有幾種找換方式。找到99塊的所有找換方式,在加上現在這裡去掉的1塊錢,就是100塊找換方式中有使用1塊的所有找換方式。

對於沒有使用1塊面額的,我們就需要看看100塊找成其它面額(不包含1塊)的找換方式。

然後將上面兩種型別的數量加起來就是100塊的所有找換方式。

可以看到,以上的思路對應的是樹形遞迴,每次遞迴呼叫分兩路,一路呼叫的找換總額減少,一路呼叫的找換幣種減少。

我的實現方法是下面這樣的,和書上略有不同。

(define (rmb-change-recursive amount change-kind change-result)

(if (= amount 0) (format #t "got one: ~s~%" change-result))

(cond ((= amount 0) 1)

((< amount 0) 0)

((= change-kind 0) 0)

(else (+ (rmb-change-recursive amount (rmb-change-next-kind change-kind) change-result)

(rmb-change-recursive (- amount change-kind) change-kind (cons change-kind change-result))))))

如果對上面的過程不理解,建議回去讀書中的1.2.2節,讀懂為止。

好的,現在才到我們真正的題目了,第乙個是找出11塊的找換方式,這種比較容易,可以按以上的方式手工列出,也可以直接執行**看看結果。

問題的第二部分比較麻煩,就是問,對於現金量的增長,以上過程的空間增長階和時間增長階是什麼?

如果對增長階的概念沒有理解透,這題很難解。

我們先開始分析一下,如果發現過程中有不理解的,需要回去書上看看增長階的內容。

首先來看看空間增長階,當我們需要計算12塊的找換方式時,比計算11塊的找換方式需要增加多少記憶體?

當然,空間增長階不能簡單理解為需要增加多少記憶體,可能會有其它的空間需要,或者人家用紙算,根本不用記憶體,我們在這裡就粗暴地將空間理解為記憶體吧。

增加多少記憶體呢?也不需要計算準確數字,只要計算大概的敏感度就好了。比如增長是線性的,多計算1塊錢就多需要100k左右的空間。又或者是二次方曲線的增長,計算11塊時需要11的二次方的空間,二計算12塊時需要12的二次方的空間。這些就是我們要求的增長階。

對於書中的count-change過程,空間增長階是多少呢?

對於遞迴過程的空間增長階,一般是去計算遞迴計算過程的最深深度。因為過程呼叫完以後,其使用的空間是會被釋放的,我們需要計算的是被那些一直遞迴呼叫自己,目前還沒有返回的過程所占用的空間。

同時需要注意每次遞迴呼叫的引數有沒有累加,累加的形式是什麼。

以上過程的遞迴巢狀最深的就是全部用1塊來找換,巢狀深度就是要找換的金錢量,11塊就是巢狀了11層,100塊就是巢狀100層。而呼叫過程中引數沒有累加,只是不斷替換而已。

所以,count-change過程的空間增長階是theta[n]。

不過,我這裡設計的過程好像有點不一樣,為了列印所有可能的找換方式,我定義了乙個引數用於儲存目前計算過的暫時可行的零錢組合,就是引數change-resule。這個引數占用的空間是如何變化的呢?

可以發現,這個引數中的元素最多的時候就是全部找成1元的時候,這時候change-result中的值是:(1 1 1 ….  1)共有n個。而每次遞迴呼叫都有乙個列表需要暫時保留,所以,當遞迴呼叫到最深層的時候,其實有n個列表,分別是(1)    (1 1)   (1 1 1) …..   (1 1 1 1 …. 1 1),所以這裡占用的空間是1到n的累加。

所以我的rmb-change過程的空間增長階是theta[n的累加],因為在求增長階的時候只取多項式中最高端的那項,theta[n]就被忽略了。

以上是空間增長階,那麼步數的增長階呢?或者說是時間增長階呢?

書中習題要求的是步數的增長階,我們一般假設執行計算的每一步都消耗等同的時間,所以時間的增長階和步數的增長階應該是一致的。有關這個假設是否正確後面的習題還有詳細的討論,目前暫時認為時間增長階和步數的增長階相同。

這個增長階的求解過程比較複雜,我也到網上參考了好多別人的解法,有許多種思路。我總結了乙個我個人比較容易理解的解法,描述如下:

以我這裡的例子,找換面額種類有7種,分別是「1元」,「2元」,「5元」,「10元」,「20元」,「50元」,「100元」。

為了方便表達,我們用函式(t n m)來表示以上過程的時間複雜度,其中n是需要找換金額總數量,m是用於找換的零錢的面額的種類數量。

如果把1000元錢進行找換,可以把1000元的找換方式分為 「使用1元的」  和  「不使用1元的」 兩種方式,就是:

(t 1000 7) = (t 999 7) + (t 1000 6)

而999元的找換方式又可以分為 「使用1元的」  和  「不使用1元的」 兩種方式,就是:

(t 999 7) = (t 998 7) + (t 999 6)

如此不斷分解,就可以得到1000個分支,每個分支帶乙個(t n 6)。

也就是所這裡的(t  n 7) =  1000 * (t n 6)   =   n * (t n 6)

再來計算(t n 6),在這裡也就是( t 1000 6)

就是把1000元找換成

「2元」,「5元」,「10元」,「20元」,「50元」,「100元」這6種零錢。

按上面相同的方法有:

(t 1000 6) = (t 998 6) + (t 1000 5)

(t 996 6) = (t 996 6) + (t 1000 5)

(t 994 6) = (t 994 6) + (t 1000 5)

....

按以上方法可以拆出500個分支(就是n/2個分支,因為這次是從2元開始找),每個分支帶乙個(t 1000 5)。

就有(t 1000 6) = n/2 * ( t 1000 5)

以此類推就有(t 1000 7) = n * ( n/2 * ( n/5 * ( n/10 * ( n/20 * (n/50 * (n/100)))))),其中的除數就是各個面額。

就有(t 1000 7 ) = (n 的 7次方)/10000000

因為我們在求增長階,所以直接取增長階為 (n 的 7次方)

雖然除數10000000也算是個很大的數,不過在n大到一定程度時,(

n 的 7次方)就變成乙個超級大的數,這時10000000也就不算什麼了。

這同時也符合我們觀察到的現象,當n很小時,實際需要的步數遠小於(

n 的 7次方)。

SICP 習題 1 22 解題總結

sicp 習題 1.22 要求改進題中列舉出來檢查素數的過程,用來求1000,10000,100 000,還有1000 000附近的素數,然後比較求這些素數的時間,看是否符合 n 的複雜度。要完成這道題首先要將題目中列出的過程照抄到你的scheme環境中。因為書中的 使用了 runtime 過程,我...

SICP 習題 1 25 解題總結

sicp 習題 1.25 就是我上面說過的傷自尊的題了。習題1.25說到有個叫allyssa p.hacker的人說expmod過程完全沒有必要搞那麼麻煩,直接使用前面的fast expt過程和remainder過程就好了,她 叫alyssa的應該是女的吧 覺得可以這樣定義expmod define...

SICP 習題 (1 29)解題總結

sicp 習題 1.29 要求辛普森規則求函式f在範圍a 和 b之間的定積分的近似值。在經過前面習題的磨練之後,我對這種充滿數學定義的題目已經麻木了,覺得自己能完成題目就行,有些時候不需要去理會哪些折磨人的數學定義,比如什麼函式的定積分,更不用說什麼辛普森規則。其實sicp在1.3.1這節主要講的是...