Code Review

Compare your solutions

    #|
  Упражнение 3.23

  Дек (deque, double-ended deque, «двусторонняя очередь») представляет собой последовательность,
  элементы в которой могут добавляться и уничтожаться как с головы, так и с хвоста. На деках определены
  такие операции: конструктор make-deque, предикат empty-deque?, селекторы front-deque и rear-deque, и
  мутаторы front-insert-deque!, rear-insert-deque!, front-delete-deque! и rear-delete-deque!. Покажите,
  как представить дек при помощи пар, и напишите реализацию операций. Все операции должны выполняться
  за Θ(1) шагов.
|#

(#%require rackunit)

(define (make-deque) (mcons '() '()))

(define (front-ptr deque) (mcar deque))

(define (rear-ptr deque) (mcdr deque))

(define (set-front-ptr! deque item)
  (set-mcar! deque item))

(define (set-rear-ptr! deque item)
  (set-mcdr! deque item))

(define (empty-deque? deque)
  (null? (front-ptr deque)))

(define (front-deque deque)
  (if (empty-deque? deque)
      (error "FRONT called with an empty deque" deque)
      (item-value (front-ptr deque))))

(define (rear-deque deque)
  (if (empty-deque? deque)
      (error "REAR called with an empty deque" deque)
      (item-value (rear-ptr deque))))

(define (item-value item)
  (mcar (mcar item)))

(define (item-next item)
  (mcdr (mcar item)))

(define (item-prev item)
  (mcdr item))

(define (set-item-next! item next)
  (set-mcdr! (mcar item) next))

(define (set-item-prev! item prev)
  (set-mcdr! item prev))

(define (make-item value next prev)
  (mcons (mcons value next) prev))

(define (rear-insert-deque! deque value)
  (let ((new-item (make-item value '() '())))
    (cond ((empty-deque? deque)
           (set-front-ptr! deque new-item)
           (set-rear-ptr! deque new-item)
           deque)
          (else
           (set-item-prev! (rear-ptr deque) new-item)
           (set-item-next! new-item (rear-ptr deque))
           (set-rear-ptr! deque new-item)
           deque))))

(define (front-insert-deque! deque value)
  (let ((new-item (make-item value '() '())))
    (cond ((empty-deque? deque)
           (set-front-ptr! deque new-item)
           (set-rear-ptr! deque new-item)
           deque)
          (else
           (set-item-prev! new-item (front-ptr deque))
           (set-item-next! (front-ptr deque) new-item)
           (set-front-ptr! deque new-item)
           deque))))

(define (front-delete-deque! deque)
  (cond ((empty-deque? deque)
         (error "DELETE! called with an empty deque" deque))
        (else
         (let ((prev (item-prev (front-ptr deque))))
           (set-front-ptr! deque prev)
           (if (null? prev)
               (set-rear-ptr! deque '())
               (set-item-next! prev '()))
         deque))))

(define (rear-delete-deque! deque)
  (cond ((empty-deque? deque)
         (error "DELETE! called with an empty deque" deque))
        (else
         (let ((next (item-next (rear-ptr deque))))
           (set-rear-ptr! deque next)
           (if (null? next)
               (set-front-ptr! deque '())
               (set-item-prev! next '()))
         deque))))

(define dq1 (make-deque))

(check-true (empty-deque? dq1))

(front-insert-deque! dq1 'a)

(check-false (empty-deque? dq1))

(check-equal? (front-deque dq1) 'a)
(check-equal? (rear-deque dq1) 'a)

(rear-insert-deque! dq1 'b)

(check-equal? (front-deque dq1) 'a)
(check-equal? (rear-deque dq1) 'b)

(front-delete-deque! dq1)

(check-equal? (front-deque dq1) 'b)
(check-equal? (rear-deque dq1) 'b)

(front-delete-deque! dq1)

(check-true (empty-deque? dq1))

(define dq2 (make-deque))

(front-insert-deque! dq2 3)
(front-insert-deque! dq2 2)
(front-insert-deque! dq2 1)

(check-equal? (front-deque dq2) 1)
(check-equal? (rear-deque dq2) 3)

(rear-delete-deque! dq2)

(check-equal? (front-deque dq2) 1)
(check-equal? (rear-deque dq2) 2)

(rear-delete-deque! dq2)

(check-equal? (front-deque dq2) 1)
(check-equal? (rear-deque dq2) 1)

(rear-delete-deque! dq2)

(check-true (empty-deque? dq2))