3.3.2 キューの表現
キューの実装
(define (front-ptr queue) (car queue)) (define (rear-ptr queue) (cdr queue)) (define (set-front-ptr! queue item) (set-car! queue item)) (define (set-rear-ptr! queue item) (set-cdr! queue item)) (define (empty-queue? queue) (null? (front-ptr queue))) (define (make-queue) (cons '() '())) (define (front-queue queue) (if (empty-queue? queue) (error "FRONT called with an empty queue" queue) (car (front-ptr queue)))) (define (insert-queue! queue item) (let ((new-pair (cons item '()))) (cond ( (empty-queue? queue) (set-front-ptr! queue new-pair) (set-rear-ptr! queue new-pair) queue ) (else (set-cdr! (rear-ptr queue) new-pair) (set-rear-ptr! queue new-pair) queue)) ) ) (define (delete-queue! queue) (cond ( (empty-queue? queue) (error "DELETE! called with an empty queue" queue)) (else (set-front-ptr! queue (cdr (front-ptr queue))) queue)))
演習問題
Exercise 3.21
実際のQueueの状態をみるためのprint-queueの実装
二つ目のやつは、O(1)で最後のポインタにアクセスするためにあるやつ
(define q1 (make-queue)) (print q1) (insert-queue! q1 'a) (print q1) (insert-queue! q1 'b) (print q1) (delete-queue! q1) (print q1) ;(()) ;((a) a) ;((a b) b) ;((b) b) (define (print-queue queue) (print (front-ptr queue)) )
テスト
(define q1 (make-queue)) (print-queue q1) (insert-queue! q1 'a) (print-queue q1) (insert-queue! q1 'b) (print-queue q1) (delete-queue! q1) (print-queue q1) ;() ;(a) ;(a b) ;(b)
consを使ってキューを表現しているため、 queueオブジェクトをprintすると、先頭ポインタ + 最後のポインタが表示されてしまう。 キューの状態だけみたいのであれば、先頭ポインタからの後続データ構造だけを表示すれば良い。
Exercise 3.22
キューは、ポインタのペアとして表現する以外に、 局所状態を持つ⼿続きとして構築することもできる。 局所状態は通常のリストの先端と終端へのポインタからなる。 make-queue の定義を完成させ、この表現によるキューの演算を実装せよ。
(define (make-queue) (let ( (front-ptr '()) (rear-ptr '()) ) (define (set-front-ptr! item) (set! front-ptr item)) (define (set-rear-ptr! item) (set! rear-ptr item)) (define (empty-queue?) (null? front-ptr)) (define (front-queue) (if (empty-queue?) (error "FRONT called with an empty queue" 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) queue)) ) ) (define (delete-queue!) (cond ( (empty-queue?) (error "DELETE! called with an empty queue" queue)) (else (set-front-ptr! (cdr front-ptr))))) (define (print-queue) (print 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!) ((eq? m 'print-queue) print-queue) )) dispatch))
テスト
(define queue (make-queue)) ((queue 'insert-queue!) 'a) ((queue 'print-queue)) ((queue 'insert-queue!) 'b) ((queue 'print-queue)) (print ((queue 'front-queue))) ((queue 'delete-queue!)) ((queue 'print-queue)) ((queue 'delete-queue!)) ((queue 'print-queue)) ;((queue 'delete-queue!)) ;((queue 'print-queue)) ;(a) ;(a b) ;a ;(b) ;() ;*** ERROR: DELETE! called with an empty queue #<closure ((make-queue dispatch) m)> ; While loading "./3.3.2.scm" at line 138 ;Stack Trace:
Execise 3.23
両端キュー (deque)(“double-ended queue”) は、先端と終端のどちらに対しても項⽬の挿⼊と削除が⾏える列である。 deque に対する演算は、 コンストラクタ make-deque、述語 empty-deque?、 セレクタ front-deque、rear-deque、 ミューテータ front-insert-deque!,rear-insert-deque!, front-deletedeque!, rear-delete-deque! である。 ペアによって deque を表現するやり⽅を⽰せ。また、演算を実装せよ。 全ての演算は Θ(1)ステップで完了しなければならない。
Schemeでかく能力がなかったのでPythonで書いた(´・ω・`)
def ex_3_23(): class Item: def __init__(self, value): self.value = value self.prev = None self.next = None def __repr__(self): return '<Item {}>'.format(self.value) class Deque: def __init__(self): self.front = None self.rear = None def empty_queue(self): return self.front is None # Selector def front_deque(self): return self.front.value def rear_deque(self): return self.rear.value # Mutator def front_insert_deque(self, value): item = Item(value) if self.front: item.next = self.front self.front.prev = item else: self.rear = item self.front = item def rear_insert_deque(self, value): item = Item(value) if self.rear: item.prev = self.rear self.rear.next = item else: self.front = item self.rear = item def front_delete_queue(self): if self.front is None: raise Exception('Queue is empty.') if self.front is self.rear: self.rear = None self.front = self.front.next if self.front: self.front.prev = None def rear_delete_queue(self): if self.rear is None: raise Exception('Queue is empty.') if self.front is self.rear: self.front = None self.rear = self.rear.prev if self.rear: self.rear.next = None def print_queue(self): q = self.front a = [] while q is not None: a.append(q.value) q = q.next print(a) deque = Deque() deque.front_insert_deque(1) deque.front_insert_deque(2) deque.print_queue() # [2, 1] deque.rear_insert_deque(3) deque.print_queue() # [2, 1, 3] deque.front_delete_queue() deque.print_queue() # [1, 3] deque.rear_delete_queue() deque.print_queue() # [1] deque.rear_delete_queue() # deque.rear_delete_queue() # Exception: Queue is empty. ex_3_23()