キュークラス(enqueue と dequeue)
前回は、インスタンスの中にリストを 1 本持たせました。今回は、そのリストに触るメソッドの側を決めます。
中身が同じなのに、出てくる答えが違う
1, 2, 3 をこの順に入れた入れ物が 2 つあります。片方から取り出すと 3、もう片方から取り出すと 1 が出ます。中に入っているリストは、どちらも [1, 2, 3] でまったく同じです。
| 種類 | 入れる場所 | 取り出す場所 |
|---|---|---|
| スタック | 末尾 | 末尾 |
| キュー | 末尾 | 先頭 |
違うのはメソッドの中身だけです。データ構造の正体は、持っているデータではなく、そのデータに許した操作のほうにあります。列に並ぶ人の流れ、印刷の順番待ち、幅優先探索の訪問順は、どれも先に入ったものが先に出る FIFO です。
メソッドは、状態をどう変えるかを名前で約束する
Python
class Lamp:
def __init__(self):
self.on = False
def toggle(self):
self.on = not self.on
def turn_off(self):
self.on = Falsetoggle は反転、turn_off は必ず消灯です。使う側は self.on を直接書き換えず、どちらのメソッドを呼ぶかだけを決めます。同じ on という 1 つの属性でも、用意するメソッドを変えれば、まったく違う部品になります。
メソッド越しにする利点は、呼ぶ側が中の形を知らずに済むことです。あとで on を明るさの数値に作り替えても、turn_off を呼んでいる側は 1 行も変わりません。差し替えられる余地は、外に見せる操作を絞ったぶんだけ残ります。
先頭から抜くと、後ろが全部ずれる
リストの先頭を取り除く道具は、言語ごとに用意されています。
Python
items = [1, 2, 3]
first = items.pop(0) # first は 1、items は [2, 3]JavaScript
const items = [1, 2, 3];
const first = items.shift(); // first は 1、items は [2, 3]どちらも、抜いたあとに残り全部を 1 つずつ前へ詰め直します。要素が n 個あれば n 回ずらします。末尾から抜くときは最後の 1 個を外すだけなので、詰め直しは起きません。同じ配列を使っていても、どちらの端を触るかで手間が変わる、というのがここでの発見です。
やってみよう
queueOps(ops) を書いてください。中にクラスを 1 つ定義し、末尾に加えるメソッドと、先頭から取り除くメソッドを持たせます。ops の各要素は ["enqueue", 5] か ["dequeue"] です。取り除いた値は捨てて構いません。最後に内部のリストを配列で返します。空の状態で取り除く操作は来ません。
要件
- 関数
queueOps(ops)を実装し、操作後のキュー内容を配列で返す - 内部に
Queueクラスを定義し、enqueue/dequeueメソッドを持たせる - ops の各要素は
["enqueue", value]または["dequeue"]の形に対応する
入出力例
queueOps([["enqueue",1],["enqueue",2],["dequeue"],["enqueue",3]]) → [2,3]
queueOps([["enqueue",5],["enqueue",10],["enqueue",15],["enqueue",20]]) → [5,10,15,20]
queueOps([["enqueue",1],["enqueue",2],["dequeue"],["dequeue"],["enqueue",99]]) → [99]
queueOps([["enqueue",1],["dequeue"],["enqueue",2],["dequeue"],["enqueue",3]]) → [3]
queueOps([["enqueue",42]]) → [42]