SICP Exercise 3.23
Question
A deque (“double-ended queue”) is a sequence in which items can be inserted
and deleted at either the front or the rear. Operations on deques are the
constructor make-deque
, the predicate empty-deque?
, selectors front-deque
and rear-deque
, and mutators front-insert-deque!
, rear-insert-deque!
,
front-delete-deque!
, rear-delete-deque!
. Show how to represent deques using
pairs, and give implementations of the operations. All operations should be
accomplished in \(\Theta(1)\) steps.
Answer
This would be really easy if it weren’t for rear-delete-queue
, which is hard
to do in \(\Theta(1)\) time, since you need to get the second-to-last pair in the
list.
In order to solve this problem, we need to use a double linked list as our
basic structure. This uses a three-part structure which I will call a node
containing first the value, then the previous element and then the next
element. Here are the helper functions for our nodes
:
(define (make-node val prev next)
(list val prev next))
(define (val-node node) (car node))
(define (prev-node node) (cadr node))
(define (next-node node) (caddr node))
(define (set-val-node! node x)
(set-car! node x))
(define (set-prev-node! node x)
(set-car! (cdr node) x))
(define (set-next-node! node x)
(set-car! (cddr node) x))
With this, we can now implement the deque
logic.
(define (make-deque)
(let ((front-ptr '())
(rear-ptr '()))
(define (empty-deque?)
(or (null? front-ptr) (null? rear-ptr)))
(define (front-deque)
(if (empty-deque?)
(error "FRONT called with an empty deque")
(car front-ptr)))
(define (rear-deque)
(if (empty-deque?)
(error "REAR called with an empty deque")
(car rear-ptr)))
(define (set-front-ptr! i)
(set! front-ptr i))
(define (set-rear-ptr! i)
(set! rear-ptr i))
(define (front-insert-deque! i)
(let ((new-node (make-node i '() '())))
(cond ((empty-deque?)
(set-front-ptr! new-node)
(set-rear-ptr! new-node))
(else
(set-next-node! new-node front-ptr)
(set-prev-node! front-ptr new-node)
(set-front-ptr! new-node)))))
(define (rear-insert-deque! i)
(let ((new-node (make-node i '() '())))
(cond ((empty-deque?)
(set-front-ptr! new-node)
(set-rear-ptr! new-node))
(else
(set-prev-node! new-node rear-ptr)
(set-next-node! rear-ptr new-node)
(set-rear-ptr! new-node)))))
(define (front-delete-deque!)
(cond ((empty-deque?)
(error "FRONT-DELETE! called with an empty deque"))
((null? (next-node front-ptr))
(set-front-ptr! '()))
(else
(set-front-ptr! (next-node front-ptr))
(set-prev-node! front-ptr '()))))
(define (rear-delete-deque!)
(cond ((empty-deque?)
(error "REAR-DELETE! called with an empty deque"))
(else
(set-rear-ptr! (prev-node rear-ptr))
(set-next-node! rear-ptr '()))))
(define (dispatch m)
(cond ((eq? m 'front-insert-deque!) front-insert-deque!)
((eq? m 'rear-insert-deque!) rear-insert-deque!)
((eq? m 'front-delete-deque!) (front-delete-deque!))
((eq? m 'rear-delete-deque!) rear-delete-deque!)
((eq? m 'front-deque) (front-deque))
((eq? m 'rear-deque) (rear-deque))
((eq? m 'front-ptr) front-ptr)
(else
(error "UNKNOWN METHOD -- make-deque"))))
dispatch))