SICP 読み (108) 3.3.2 キューの表現
double-ended queue な課題
問題 3.23
以下の手続きがあれば良い、と。
- make-deque
- empty-deque?
- front-deque
- rear-deque
- front-insert-deque!
- rear-insert-deque!
- front-delete-deque!
- rear-delete-deque!
とりあえず元のソレをコピって作ってみるか、とゆー事で以下が試験ですが、(106) の差分のみ。
("rear-queue test" ("empty-queue" (assert-error (lambda() (rear-queue '(())))) ) ("normal" (let ((q (cons (cons 1 '()) '()))) (assert-equal 1 (rear-queue q))) ) )
あと、insert! とか delete! のあたりは以下のように。
("front-insert-queue! test" ("front-insert" (let ((q (make-queue))) (front-insert-queue! q 1) (assert-equal 1 (front-queue q)) (assert-equal 1 (rear-queue q)) (front-insert-queue! q 2) (assert-equal 2 (front-queue q)) (assert-equal 1 (rear-queue q)) (front-insert-queue! q 3) (assert-equal 3 (front-queue q)) (assert-equal 1 (rear-queue q)) (front-insert-queue! q 4) (assert-equal 4 (front-queue q)) (assert-equal 1 (rear-queue q)) ) ) ) ("rear-insert-queue! test" ("rear-insert" (let ((q (make-queue))) (rear-insert-queue! q 1) (assert-equal 1 (front-queue q)) (assert-equal 1 (rear-queue q)) (rear-insert-queue! q 2) (assert-equal 1 (front-queue q)) (assert-equal 2 (rear-queue q)) (rear-insert-queue! q 3) (assert-equal 1 (front-queue q)) (assert-equal 3 (rear-queue q)) (rear-insert-queue! q 4) (assert-equal 1 (front-queue q)) (assert-equal 4 (rear-queue q)) ) ) ) ("front-delete-queue! test" ("front-delete" (let ((q (make-queue))) (rear-insert-queue! q 1) (rear-insert-queue! q 2) (assert-equal 1 (front-queue q)) (front-delete-queue! q) (assert-equal 2 (front-queue q)) (rear-insert-queue! q 3) (assert-equal 2 (front-queue q)) (front-delete-queue! q) (assert-equal 3 (front-queue q)) (front-delete-queue! q) (assert-true (empty-queue? q))) ) ) ("rear-delete-queue! test" ("rear-delete" (let ((q (make-queue))) (front-insert-queue! q 1) (front-insert-queue! q 2) (assert-equal 2 (front-queue q)) (rear-delete-queue! q) (assert-equal 1 (front-queue q)) (front-insert-queue! q 3) (assert-equal 3 (front-queue q)) (rear-delete-queue! q) (assert-equal 1 (front-queue q)) (rear-delete-queue! q) (assert-true (empty-queue? q))) ) )
うーん。なんか微妙。がしかし構わず実装に移る。
続き
って全部 O(1) で処理するってコトは、これまでに出てきた queue の実装だと rear-delete がどうにもならんぞ。つーコトは上記の試験では微妙だな。双方向リストだったら簡単、とゆーのは想像に難くないんですがどうすりゃ良いやら。
あるいは、insert する時の先頭 (又は末端) は保管しとく、とか?? (なんか微妙
# げ。これじゃ二コ前の末端とか分からんし。(駄目
とりあえず動きそうな感じのアイデアをひり出しはしたのですが、試験はそのままで (とは言え queue を deque にしてます)。
そのまた続き
O(1) にしろ、とゆーのはキビシいな。直上で_動きそう_と書いたソレは結局の所、削除において O(n) になる事が判明。無理矢理双方向リストをでっち上げる事に。
基本的には car には値で、cdr に前と後の要素へのポインタ、な方向で。
以下が試験
#!/usr/bin/env gosh (use test.unit) (require "3.3.2") (define-test-suite "3.3.2" ("make-deque test" ("(make-deque) returns '(())" (assert-equal '(()) (make-deque)) ) ("(front-ptr (make-deque)) returns '()" (let ((q (make-deque))) (assert-equal '() (front-ptr q))) ) ("(rear-ptr (make-deque)) returns '()" (let ((q (make-deque))) (assert-equal '() (rear-ptr q))) ) ("empty-deque? returns true" (let ((q (make-deque))) (assert-true (empty-deque? q))) ) ("front-deque error" (let ((q (make-deque))) (assert-error (lambda () (front-deque q)))) ) ("rear-deque error" (let ((q (make-deque))) (assert-error (lambda () (rear-deque q)))) ) ) ("front-ptr test" ("return (car deque)" (assert-equal 'car (front-ptr (cons 'car 'cdr))) ) ) ("rear-ptr test" ("return (cdr deque)" (assert-equal 'cdr (rear-ptr (cons 'car 'cdr))) ) ) ("set-front-ptr! test" ("set-car!" (let ((q (cons 'car 'cdr))) (set-front-ptr! q 'change) (assert-equal 'change (front-ptr q))) ) ) ("set-rear-ptr! test" ("set-cdr!" (let ((q (cons 'car 'cdr))) (set-rear-ptr! q 'change) (assert-equal 'change (rear-ptr q))) ) ) ("empty-deque? test" ("empty" (assert-true (empty-deque? '(()))) ) ("not empty" (assert-false (empty-deque? (cons 'a '()))) ) ) ("front-deque test" ("empty deque" (assert-error (lambda () (front-deque '(())))) ) ("normal" (let ((i (cons 1 (cons '() '())))) (let ((q (cons i i))) (assert-equal 1 (front-deque q)))) ) ) ("rear-deque test" ("empty-deque" (assert-error (lambda() (rear-deque '(())))) ) ("normal" (let ((i (cons 1 (cons '() '())))) (let ((q (cons i i))) (assert-equal 1 (rear-deque q)))) ) ) ("front-insert-deque! test" ("front-insert" (let ((q (make-deque))) (front-insert-deque! q 1) (assert-equal 1 (front-deque q)) (assert-equal 1 (rear-deque q)) (front-insert-deque! q 2) (assert-equal 2 (front-deque q)) (assert-equal 1 (rear-deque q)) (front-insert-deque! q 3) (assert-equal 3 (front-deque q)) (assert-equal 1 (rear-deque q)) (front-insert-deque! q 4) (assert-equal 4 (front-deque q)) (assert-equal 1 (rear-deque q)) ) ) ) ("rear-insert-deque! test" ("rear-insert" (let ((q (make-deque))) (rear-insert-deque! q 1) (assert-equal 1 (front-deque q)) (assert-equal 1 (rear-deque q)) (rear-insert-deque! q 2) (assert-equal 1 (front-deque q)) (assert-equal 2 (rear-deque q)) (rear-insert-deque! q 3) (assert-equal 1 (front-deque q)) (assert-equal 3 (rear-deque q)) (rear-insert-deque! q 4) (assert-equal 1 (front-deque q)) (assert-equal 4 (rear-deque q)) ) ) ) ("front-delete-deque! test" ("front-delete" (let ((q (make-deque))) (rear-insert-deque! q 1) (rear-insert-deque! q 2) (assert-equal 1 (front-deque q)) (front-delete-deque! q) (assert-equal 2 (front-deque q)) (rear-insert-deque! q 3) (assert-equal 2 (front-deque q)) (front-delete-deque! q) (assert-equal 3 (front-deque q)) (front-delete-deque! q) (assert-true (empty-deque? q))) ) ) ("rear-delete-deque! test" ("rear-delete" (let ((q (make-deque))) (front-insert-deque! q 1) (front-insert-deque! q 2) ;; 2 -> 1 (assert-equal 2 (front-deque q)) (rear-delete-deque! q) ;; 2 (assert-equal 2 (front-deque q)) (front-insert-deque! q 3) ;; 3 -> 2 (assert-equal 3 (front-deque q)) (rear-delete-deque! q) ;; 3 (assert-equal 3 (front-deque q)) (rear-delete-deque! q) ;; (assert-true (empty-deque? q))) ) ) )
で、微妙な実装が以下。DRY 違反満載
(define (front-ptr deque) (car deque)) (define (rear-ptr deque) (cdr deque)) (define (set-front-ptr! deque item) (set-car! deque item)) (define (set-rear-ptr! deque item) (set-cdr! deque item)) (define (empty-deque? deque) (null? (front-ptr deque))) (define (make-deque) (cons '() '())) (define (front-deque deque) (if (empty-deque? deque) (error "FRONT called with an empty deque" deque) (car (front-ptr deque)))) (define (rear-deque deque) (if (empty-deque? deque) (error "FRONT called with an empty deque" deque) (car (rear-ptr deque)))) (define (front-insert-deque! deque item) (let ((new-pair (cons item (cons '() '())))) (cond ((empty-deque? deque) (set-front-ptr! deque new-pair) (set-rear-ptr! deque new-pair) deque) (else (set-car! (cdr (front-ptr deque)) new-pair) (set-cdr! (cdr new-pair) (front-ptr deque)) (set-front-ptr! deque new-pair) deque)))) (define (rear-insert-deque! deque item) (let ((new-pair (cons item (cons '() '())))) (cond ((empty-deque? deque) (set-front-ptr! deque new-pair) (set-rear-ptr! deque new-pair) deque) (else (set-car! (cdr new-pair) (rear-ptr deque)) (set-cdr! (cdr (rear-ptr deque)) new-pair) (set-rear-ptr! deque new-pair) deque)))) (define (front-delete-deque! deque) (cond ((empty-deque? deque) (error "DELETE! called with an empty deque" deque)) (else (cond ((eq? (front-ptr deque) (rear-ptr deque)) (set-front-ptr! deque '()) (set-rear-ptr! deque '()) deque) (else (set-front-ptr! deque (cdr (cdr (front-ptr deque)))) deque))))) (define (rear-delete-deque! deque) (cond ((empty-deque? deque) (error "DELETE! called with an empty deque" deque)) (else (cond ((eq? (front-ptr deque) (rear-ptr deque)) (set-front-ptr! deque '()) (set-rear-ptr! deque '()) deque) (else (set-rear-ptr! deque (car (cdr (rear-ptr deque)))) deque))))) (define (print-deque q) (let f ((q (front-ptr q)) (l '())) (if (null? (cdr (cdr q))) l (f (cdr (cdr q)) (cons (car q) l)))))
別途、もう少し見直しが必要。
さらに追記
面白そうなんで見直し。
(define (front-ptr deque) (car deque)) (define (rear-ptr deque) (cdr deque)) (define (set-front-ptr! deque item) (set-car! deque item)) (define (set-rear-ptr! deque item) (set-cdr! deque item)) (define (empty-deque? deque) (null? (front-ptr deque))) (define (make-deque) (cons '() '())) (define (end-deque deque p) (if (empty-deque? deque) (error "FRONT called with an empty deque" deque) (car (p deque)))) (define (front-deque deque) (end-deque deque front-ptr)) (define (rear-deque deque) (end-deque deque rear-ptr)) (define (insert-deque-common deque item p) (let ((new-pair (cons item (cons '() '())))) (cond ((empty-deque? deque) (set-front-ptr! deque new-pair) (set-rear-ptr! deque new-pair) deque) (else (p deque new-pair) deque)))) (define (front-insert-deque! deque item) (insert-deque-common deque item (lambda (deque new-pair) (set-car! (cdr (front-ptr deque)) new-pair) (set-cdr! (cdr new-pair) (front-ptr deque)) (set-front-ptr! deque new-pair)))) (define (rear-insert-deque! deque item) (insert-deque-common deque item (lambda (deque new-pair) (set-car! (cdr new-pair) (rear-ptr deque)) (set-cdr! (cdr (rear-ptr deque)) new-pair) (set-rear-ptr! deque new-pair)))) (define (delete-queue-common deque p) (cond ((empty-deque? deque) (error "DELETE! called with an empty deque" deque)) (else (cond ((eq? (front-ptr deque) (rear-ptr deque)) (set-front-ptr! deque '()) (set-rear-ptr! deque '()) deque) (else (p deque) deque))))) (define (front-delete-deque! deque) (delete-queue-common deque (lambda (deque) (set-front-ptr! deque (cdr (cdr (front-ptr deque))))))) (define (rear-delete-deque! deque) (delete-queue-common deque (lambda (deque) (set-rear-ptr! deque (car (cdr (rear-ptr deque))))))) (define (print-deque q) (let f ((q (front-ptr q)) (l '())) (if (null? q) l (f (cdr (cdr q)) (cons (car q) l)))))
まだ微妙。