scheme解决约瑟夫环问题(续)

    sicp的习题3.22,也就是以消息传递的风格重新实现队列,我的解答如下:

(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!)))

     由此,我才知道自己竟然一直没有想到,scheme完全可以模拟单向循环链表,整整第三章都在讲引入赋值带来的影响,而我却视而不见。在引入了改变函数 后,数据对象已经具有OO的性质,模拟链表、队列、table都变的易如反掌。首先,模拟节点对象,节点是一个序对,包括当前节点编号和下一个节点:

 

(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 (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))

     make-cycle-list生成一个有N个元素的环形链表,比如(make-cycle-list 8)的结果如下
        #0=(1 2 3 4 5 6 7 8 . #0#)

     Drscheme的输出形象地展示了这是一个循环的链表。那么约瑟夫环的问题就简单了:

 

(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)))

     从head节点开始计数,每到m,就将当前节点删除(通过将前一个节点的next-node设置为current的下一个节点),最后剩下的节点的编号就是答案。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值