scheme解決約瑟夫環(huán)問題(續(xù))
Posted on 2008-04-16 10:27 dennis 閱讀(631) 評論(0) 編輯 收藏 所屬分類: 計算機(jī)科學(xué)與基礎(chǔ) sicp的習(xí)題3.22,也就是以消息傳遞的風(fēng)格重新實(shí)現(xiàn)隊(duì)列,我的解答如下:
由此,我才知道自己竟然一直沒有想到,scheme完全可以模擬單向循環(huán)鏈表,整整第三章都在講引入賦值帶來的影響,而我卻視而不見。在引入了改變函數(shù)后,數(shù)據(jù)對象已經(jīng)具有OO的性質(zhì),模擬鏈表、隊(duì)列、table都變的易如反掌。首先,模擬節(jié)點(diǎn)對象,節(jié)點(diǎn)是一個序?qū)Γó?dāng)前節(jié)點(diǎn)編號和下一個節(jié)點(diǎn):
有了節(jié)點(diǎn),實(shí)現(xiàn)了下單向循環(huán)鏈表:
make-cycle-list生成一個有N個元素的環(huán)形鏈表,比如(make-cycle-list 8)的結(jié)果如下
#0=(1 2 3 4 5 6 7 8 . #0#)
Drscheme形象地展示了這是一個循環(huán)的鏈表。那么約瑟夫環(huán)的問題就簡單了:
從head節(jié)點(diǎn)開始計數(shù),每到m,就將當(dāng)前節(jié)點(diǎn)刪除(通過將前一個節(jié)點(diǎn)的next-node設(shè)置為current的下一個節(jié)點(diǎn)),最后剩下的節(jié)點(diǎn)的編號就是答案。
(define (make-queue)
(let ((front-ptr '())
(rear-ptr '()))
(define (set-front-ptr! ptr) (set! front-ptr ptr))
(define (set-rear-ptr! ptr) (set! rear-ptr ptr))
(define (empty-queue?) (null? front-ptr))
(define (front-queue)
(if (empty-queue?)
(error "FRONT called with an empty queue")
(car front-ptr)))
(define (insert-queue! item)
(let ((new-pair (cons item '())))
(cond ((empty-queue?)
(set-front-ptr! new-pair)
(set-rear-ptr! new-pair))
(else
(set-cdr! rear-ptr new-pair)
(set-rear-ptr! new-pair)))))
(define (delete-queue!)
(cond ((empty-queue?)
(error "DELETE! called with an empty queue" queue))
(else
(set-front-ptr! (cdr front-ptr)))))
(define (dispatch m)
(cond ((eq? m 'front-queue) (front-queue))
((eq? m 'empty-queue?) (empty-queue?))
((eq? m 'insert-queue!) insert-queue!)
((eq? m 'delete-queue!) delete-queue!)
(else
(error "Unknow method" m))))
dispatch))
(define (front-queue z) (z 'front-queue))
(define (empty-queue? z) (z 'empty-queue?))
(define (insert-queue! z item) ((z 'insert-queue!) item))
(define (delete-queue! z) ((z 'delete-queue!)))
(let ((front-ptr '())
(rear-ptr '()))
(define (set-front-ptr! ptr) (set! front-ptr ptr))
(define (set-rear-ptr! ptr) (set! rear-ptr ptr))
(define (empty-queue?) (null? front-ptr))
(define (front-queue)
(if (empty-queue?)
(error "FRONT called with an empty queue")
(car front-ptr)))
(define (insert-queue! item)
(let ((new-pair (cons item '())))
(cond ((empty-queue?)
(set-front-ptr! new-pair)
(set-rear-ptr! new-pair))
(else
(set-cdr! rear-ptr new-pair)
(set-rear-ptr! new-pair)))))
(define (delete-queue!)
(cond ((empty-queue?)
(error "DELETE! called with an empty queue" queue))
(else
(set-front-ptr! (cdr front-ptr)))))
(define (dispatch m)
(cond ((eq? m 'front-queue) (front-queue))
((eq? m 'empty-queue?) (empty-queue?))
((eq? m 'insert-queue!) insert-queue!)
((eq? m 'delete-queue!) delete-queue!)
(else
(error "Unknow method" m))))
dispatch))
(define (front-queue z) (z 'front-queue))
(define (empty-queue? z) (z 'empty-queue?))
(define (insert-queue! z item) ((z 'insert-queue!) item))
(define (delete-queue! z) ((z 'delete-queue!)))
由此,我才知道自己竟然一直沒有想到,scheme完全可以模擬單向循環(huán)鏈表,整整第三章都在講引入賦值帶來的影響,而我卻視而不見。在引入了改變函數(shù)后,數(shù)據(jù)對象已經(jīng)具有OO的性質(zhì),模擬鏈表、隊(duì)列、table都變的易如反掌。首先,模擬節(jié)點(diǎn)對象,節(jié)點(diǎn)是一個序?qū)Γó?dāng)前節(jié)點(diǎn)編號和下一個節(jié)點(diǎn):
(define (make-node n next) (cons n next))
(define (set-next-node! node next) (set-cdr! node next))
(define (set-node-number! node n) (set-car! node n))
(define (get-number node) (car node))
(define (get-next-node node) (cdr node))
(define (set-next-node! node next) (set-cdr! node next))
(define (set-node-number! node n) (set-car! node n))
(define (get-number node) (car node))
(define (get-next-node node) (cdr node))
有了節(jié)點(diǎn),實(shí)現(xiàn)了下單向循環(huán)鏈表:
(define (make-cycle-list n)
(let ((head (make-node 1 '())))
(define (make-list current i)
(let ((next-node (make-node (+ i 1) '())))
(cond ((= i n) current)
(else
(set-next-node! current next-node)
(make-list next-node (+ i 1))))))
(set-next-node! (make-list head 1) head)
head))
(let ((head (make-node 1 '())))
(define (make-list current i)
(let ((next-node (make-node (+ i 1) '())))
(cond ((= i n) current)
(else
(set-next-node! current next-node)
(make-list next-node (+ i 1))))))
(set-next-node! (make-list head 1) head)
head))
make-cycle-list生成一個有N個元素的環(huán)形鏈表,比如(make-cycle-list 8)的結(jié)果如下
#0=(1 2 3 4 5 6 7 8 . #0#)
Drscheme形象地展示了這是一個循環(huán)的鏈表。那么約瑟夫環(huán)的問題就簡單了:
(define (josephus-cycle n m)
(let ((head (make-cycle-list n)))
(define (josephus-iter prev current i)
(let ((next-node (get-next-node current)))
(cond ((eq? next-node current) (get-number current))
((= 1 i)
(set-next-node! prev next-node)
(josephus-iter prev next-node m))
(else
(josephus-iter current next-node (- i 1))))))
(josephus-iter head head m)))
(let ((head (make-cycle-list n)))
(define (josephus-iter prev current i)
(let ((next-node (get-next-node current)))
(cond ((eq? next-node current) (get-number current))
((= 1 i)
(set-next-node! prev next-node)
(josephus-iter prev next-node m))
(else
(josephus-iter current next-node (- i 1))))))
(josephus-iter head head m)))
從head節(jié)點(diǎn)開始計數(shù),每到m,就將當(dāng)前節(jié)點(diǎn)刪除(通過將前一個節(jié)點(diǎn)的next-node設(shè)置為current的下一個節(jié)點(diǎn)),最后剩下的節(jié)點(diǎn)的編號就是答案。