リスト修行 パスカルの三角形をリストで求める

今回のリスト修行のテーマはパスカルの三角形に決定〜。

SICPの問題では(combination n k)→値だったのであんまり三角形っぽくなかった!!

ちょっと不満だったので、リストで求めたい。

方針

パスカルの三角形n列を求めるには、前のn-1列のリストを必要とします。履歴が必要なので、(combination n k n-1までのリスト)というようにしてパスカルの三角形を求めていこうと思います。

ゴニョゴニョ

できたぁ〜。

(define (combination n k l)
  (cond ((= k 0) 1)
        ((= k n) 1)
        (else
          (+ (list-ref (car l) k)
             (list-ref (car l) (- k 1))))))

; (combination 3 2 '((1 2 1) (1 1) (1)))
; 3

(define (pascal-line n l)
  (define (pascal-line-iter k)
    (if (< k 0)
        '()
        (cons (combination n k l)
              (pascal-line-iter (- k 1)))))
  (pascal-line-iter n))

; (pascal-line 3 '((1 2 1) (1 1) (1)))
; (1 3 3 1)

(define (pascal n)
  (define (print l)
    (for-each
      (lambda (res)
        (display res)
        (newline))
      l))
  (define (pascal-iter m l)
    (if (= m n)
        l
        (pascal-iter (+ m 1)
                     (cons (pascal-line m l) l))))
  (print
    (reverse (pascal-iter 0 '()))))
  • 1個の値を求めるcombination
  • 一列を求めるpascal-line
  • 全体を制御し、表示するのが、pascal

リストは逆順で挿入し、reverseして、表示してます。

実行してみる

いってみよー

(pascal 20)

(1)
(1 1)
(1 2 1)
(1 3 3 1)
(1 4 6 4 1)
(1 5 10 10 5 1)
(1 6 15 20 15 6 1)
(1 7 21 35 35 21 7 1)
(1 8 28 56 70 56 28 8 1)
(1 9 36 84 126 126 84 36 9 1)
(1 10 45 120 210 252 210 120 45 10 1)
(1 11 55 165 330 462 462 330 165 55 11 1)
(1 12 66 220 495 792 924 792 495 220 66 12 1)
(1 13 78 286 715 1287 1716 1716 1287 715 286 78 13 1)
(1 14 91 364 1001 2002 3003 3432 3003 2002 1001 364 91 14 1)
(1 15 105 455 1365 3003 5005 6435 6435 5005 3003 1365 455 105 15 1)
(1 16 120 560 1820 4368 8008 11440 12870 11440 8008 4368 1820 560 120 16 1)
(1 17 136 680 2380 6188 12376 19448 24310 24310 19448 12376 6188 2380 680 136 17 1)
(1 18 153 816 3060 8568 18564 31824 43758 48620 43758 31824 18564 8568 3060 816 153 18 1)
(1 19 171 969 3876 11628 27132 50388 75582 92378 92378 75582 50388 27132 11628 3876 969 171 19 1)

うっは、すげー。

こんなパスカルの3角形があってもいいんじゃねぇの?

という変種

combinationの定義をいじる。1じゃなくてn

; ((= k n) n)

(1)
(1 1)
(2 2 1)
(3 3 4 1)
(4 5 7 6 1)
(5 7 13 12 9 1)
(6 10 21 25 20 12 1)
(7 13 32 45 46 31 16 1)
(8 17 47 77 91 77 45 20 1)
(9 21 65 122 168 168 124 64 25 1)

やべぇ。逆順で突っ込んでるのがばれた。

列を反復で書けば良かった。反省。

修正

反復バージョン

(define (pascal-line n l)
  (define (pascal-line-iter k acc)
    (if (< k 0)
        acc
        (pascal-line-iter (- k 1)
                          (cons (combination n k l) acc))))
  (pascal-line-iter n '()))

列が逆順になります。ハイ。

気を取りなおして、nじゃなくてnの二乗

; ((= k n) (* n n))

(1)
(1 1)
(1 2 4)
(1 3 6 9)
(1 4 9 15 16)
(1 5 13 24 31 25)
(1 6 18 37 55 56 36)
(1 7 24 55 92 111 92 49)
(1 8 31 79 147 203 203 141 64)
(1 9 39 110 226 350 406 344 205 81)

上たす左上になってますね。