5.5 練習問題¶
5.5.1 知識の確認¶
1. スタックとキューで最初に取り出される要素¶
空のスタック S と空のキュー Q を用意し、それぞれに同じ操作列を実行します。
手順 1:A を追加します。
手順 2:B を追加します。
手順 3:要素を一つ取り出して記録します。
手順 4:C を追加します。
手順 5:空になるまで要素を取り出して記録します。
S と Q から要素が取り出される順序をそれぞれ書き、「先入れ後出し」または「先入れ先出し」を使って違いを説明してください。
解答例
スタック S から取り出す順序は B、C、A です。A、B を追加した後、直近に追加した B を先にポップし、次に C を追加します。
その後は C、A の順にポップするため、「先入れ後出し」です。
キュー Q から取り出す順序は A、B、C です。A、B を追加した後、最も早く追加した A を先に取り出します。
次に C を追加し、その後は B、C の順に取り出すため、「先入れ先出し」です。
2. キューの末尾が配列の末端を越えたら¶
長さ 5 の循環配列でキューを実装します。配列のインデックスは 0~4 です。
現在は front = 3、size = 2 で、キューの A、B はそれぞれインデックス 3、4 にあります。
- 「
Cをエンキューする」とき、Cはどのインデックスに置きますか。その後のsizeはいくつですか。 - 続いて一回デキューすると、どの要素が取り出されますか。新しい
frontとsizeはそれぞれいくつですか。 - この時点で、先頭から末尾への論理的な順序はどうなっていますか。デキュー時に配列内のほかの要素を移動する必要はありますか。理由も説明してください。
解答例
-
新しい要素の位置は
(front + size) % 5 = (3 + 2) % 5 = 0なので、Cはインデックス 0 に置きます。エンキュー後はsize = 3です。 -
デキューでは現在の先頭
Aを取り出します。新しい先頭のインデックスは(3 + 1) % 5 = 4なので、front = 4、size = 2となります。 -
有効な要素の論理的な順序は
B、Cです。Bはインデックス 4、Cはインデックス 0 にあります。 デキューではfrontを進め、sizeを変更するだけです。循環配列では剰余を使ってインデックスを先頭に戻すため、 ほかの要素をまとめて前へ移動する必要はありません。
3. 両端キューの両側からの操作¶
ここでは、push_first は先頭への追加、push_last は末尾への追加、
pop_first は先頭からの取り出し、pop_last は末尾からの取り出しを表します。
空の両端キュー deq に、次の操作を順に実行します。
push_last(A)push_last(B)push_first(C)pop_last()push_last(D)pop_first()
- 二回の取り出しで得られる要素はそれぞれ何ですか。
- すべての操作が終わると、先頭から末尾へどの要素が残っていますか。
- 六つの操作を確認してください。末尾への追加と先頭からの削除だけを許すキューで、すべて実行できますか。できない場合は、実行できない操作を挙げてください。さらに、両端キューでは実行できるかどうかと、その理由を説明してください。
解答例
最初の三つの操作後、両端キューは先頭から末尾へ [C, A, B] となります。
-
pop_last()でBを取り出します。Dを追加すると[C, A, D]となり、pop_first()でCを取り出します。 -
最後に残るのは
[A, D]です。 -
末尾への追加と先頭からの削除だけを許すキューでは、すべての操作を実行できません。 手順 3 の
push_first(C)は先頭への追加、手順 4 のpop_last()は末尾からの削除を求めるため、どちらもこのキューで可能な操作の範囲を超えています。 両端キューは両側から追加と削除ができるので、六つの操作をすべて実行できます。
5.5.2 プログラミング演習¶
1. 括弧列の検証¶
三種類の括弧 ()、[]、{} だけからなる文字列 s が与えられます。スタックを使い、正しい括弧列かどうかを判定してください。
正しい列では、各閉じ括弧の種類が、直近のまだ対応付けられていない開き括弧の種類と一致し、 かつ走査の終了後に対応付けられていない開き括弧が残っていない必要があります。判定結果を真偽値で返してください。
解くためのヒント
- 「閉じ括弧から対応する開き括弧」への対応表を作れます
- 閉じ括弧に出会ったら、まずスタックが空でないかを確認し、次に先頭の括弧と対応するかを調べます
- 走査が終わったとき、スタックも空である必要があります