queueを実装しようとしていると思います。これにはいくつかの方法がありますが、挿入操作と削除操作の両方を一定時間 O(1) で実行する場合は、キューの前後への参照を保持する必要があります。
これらの参照をコンス セルに保持するか、私の例のようにクロージャでラップすることができます。
用語push
とpop
は通常、スタックを扱うときに使用されるため、以下のコードではこれらをenqueue
およびに変更しました。dequeue
(define (make-queue)
(let ((フロント '())
(戻る '()))
(ラムダ (msg . obj)
(cond ((eq? msg 'empty?) (null? フロント))
((eq? msg 'エンキュー!)
(if (null? フロント)
(始める
(set! フロント obj)
(set! back obj))
(始める
(set-cdr! back obj)
(set! back obj))))
((eq? msg 'dequeue!)
(始める
(let ((val (車のフロント)))
(set! フロント (cdr フロント))
ヴァル)))
((eq? msg 'queue->list) フロント)))))
make-queue
front
変数およびでキューの状態をラップするプロシージャを返しますback
。このプロシージャは、キュー データ構造のプロシージャを実行するさまざまなメッセージを受け入れます。
この手順は次のように使用できます。
> (q (make-queue) を定義)
> (空?)
#t
> (q 'エンキュー! 4)
> (空?)
#f
> (q 'エンキュー! 9)
> (q 'queue->list)
(4 9)
> (q 'デキュー!)
4
> (q 'queue->list)
(9)
これはほぼSchemeでのオブジェクト指向プログラミングです!をキュー クラスのプライベート メンバーと見なし、メッセージをメソッドと見なすfront
ことができます。back
呼び出し規則は少し古いですが、より優れた API でキューをラップするのは簡単です。
(define (enqueue! queue x)
(キュー 'エンキュー! x))
(定義 (dequeue! キュー)
(キュー 'デキュー!))
(定義 (empty-queue? キュー)
(キュー「空?)」
(定義 (queue->list queue)
(キュー 'キュー->リスト))
編集:
Eliが指摘するように、ペアはPLTスキームではデフォルトで不変です。つまり、set-car!
andはありませんset-cdr!
。コードが PLT スキームで機能するには、代わりに変更可能なペアを使用する必要があります 。標準スキーム (R4RS、R5RS、または R6RS) では、コードは変更されずに機能するはずです。