1. 程式人生 > >親和數問題--求解500萬以內的親和數之—Scheme語言實現

親和數問題--求解500萬以內的親和數之—Scheme語言實現

作者介紹了演算法,也給出瞭解釋,其思想與埃拉托色尼選篩法是一致的,埃拉托色尼選篩法是尋找一定範圍內的質數,用一個數組裡的元素表示判斷結果,用下標來表示所檢測的數字,這裡求親和數,作者也是取樣了這樣的思路,第一遍遍歷整個陣列把所有數的因子和求出來儲存到對應的下標中,第二遍就判斷是否是親和數,這個解題的思想很巧妙,充分利用了陣列的下標。這裡我不討論作者的程式,作者用C和JAVA實現了演算法,下午我用scheme語言實現了這個演算法,這裡就拿出來看看:

#!/usr/bin/guile -s
!#
;vector initialized with 1
(define SIZE 5000000)
(define sum (make-vector SIZE 1))

(define (all-sum i)
   (define (estra j)
      (if (< j SIZE)
      (begin (vector-set! sum j (+ (vector-ref sum j) i))
             (estra (+ j i)))))
   (if (< (+ i i) SIZE)
    (begin
       (estra (+ i i))
       (all-sum (+ i 1)))
    ))
;
(all-sum 2)

(define (amiable i)
  (if (< i SIZE)
    (begin
      (if (and (> (vector-ref sum i) i) (< (vector-ref sum i) SIZE) (= (vector-ref sum (vector-ref sum i)) i)) (begin (display i) (display " ") (display (vector-ref sum i)) (newline)))
      (amiable (+ i 1)))))

(amiable 220)

這裡解釋一下程式,(all-sum i) 求解所有數的因子和,結果儲存在全域性變數sum中,all-sum本身是採用遞迴實現的,因為Scheme中很少使用迴圈,迴圈一般都使用遞迴的寫法,由於Scheme對於為尾遞迴做了優化,所以效能上不會差。在(all-sum)中又定義了一個潛逃的函式,這個函式本身也是遞迴實現的,這兩個函式實現的效果就相當於C語言中巢狀迴圈效果是一樣的,由於兩個都是尾遞迴,所以都會被優化,內層的函式使用了外層函式的變數i,這在Scheme中叫做閉包性質,也就是內層的自由變數繫結外層函式的限定變數。

最後一個函式amiable就直接判斷是否是親和數,也是一個遞迴實現,可見使用Scheme程式設計程式中會大量出現遞迴的使用,並且Scheme也提倡使用尾遞迴,因為編譯器已經做了特殊的優化,會展開為迭代。

第一次用Scheme實現了真正的功能,感覺還是隻掌握了皮毛,對Scheme理解還是很淺,希望以後隨著學習的深入能掌握的更好。