擬似言語のフラグ変数(論理型)の使い方とは?見つかったかどうかを覚えておく処理を解説
論理型の変数が true になったり false になったりして、結局それが何を表しているのか分からない。
擬似言語の問題で、見つかった や フラグ という名前の変数に出会って、手が止まったことはありませんか?
数を数える変数なら意味が分かります。ところが真と偽しか入らない変数は、何のために置かれているのかが見えにくいものです。
でも大丈夫です。フラグの役割はたった一つ、あることが起きたかどうかを覚えておくことだけです。
私はエンジニアとして10年以上、Webシステムの開発や運用に携わってきました。実務でも、処理が成功したかどうかを覚えておく変数の初期化を書き忘れて、前回の結果を引きずる不具合を調べたことがあります。
小さな変数ですが、置き場所と初期化の順番で結果がまるごと変わります。だからこそ科目Bでも、フラグは空欄の候補としてよく狙われます。
この記事では、擬似言語のフラグ変数を、探索の処理と多重ループの二つの場面から組み立てていきます。
フラグ変数とは、途中経過を覚えておく変数¶
はじめに、フラグという言葉の意味から押さえましょう。旗を上げるか下ろすかで状態を示す、あの旗が語源です。
プログラムでは、ある出来事が起きたかどうかを記録しておく変数を指します。値は真か偽のどちらかです。
擬似言語では論理型の変数として宣言し、true と false を入れて使います。数値ではなく、成立したかどうかそのものを持つ変数だと考えてください。
型の宣言そのものがあいまいなままだと、この先が読みにくくなります。整数型や論理型の書き分けに不安があれば、こちらで土台を固めておいてください。
【関連記事】擬似言語の変数宣言とデータ型の読み方|整数型・実数型・文字列型・論理型の違いを解説
なぜわざわざ覚えさせるのか¶
そもそも、どうして覚えておく必要があるのでしょうか。理由は、繰返しの中で分かったことが、繰返しを抜けた後には消えてしまうからです。
たとえば配列を先頭から調べて、探している値があるかどうかを判断する処理を考えます。ループの中では、その一件が一致したかどうかしか分かりません。
全部を見終わった後で、結局あったのかなかったのかを答える必要があります。そこで、一度でも一致したという事実を変数に残しておくわけです。
ループの外へ情報を持ち出すための小さな入れ物。これがフラグの正体です。
真と偽の二つしかないから扱いやすい¶
論理型の値は true と false の二つだけです。ここが整数型との大きな違いになります。
値が二つしかないので、if の条件にそのまま置けます。if (見つかった = true) と書かなくても、if (見つかった) だけで通じるのはこのためです。
否定したいときは not を付けます。まだ見つかっていない状態を表したいなら not 見つかった と書きます。
and や or と組み合わせた条件の読み方に自信がない人は、こちらの記事を先に通しておくと、この後のコードがすんなり入ってきます。
【関連記事】擬似言語の論理演算(and・or・not)の読み方|複合条件で迷わないコツを解説
探索の結果をフラグで覚える¶
ここから実際のコードを見ていきます。配列の中に探している値があるかどうかを調べる処理です。
data という配列に5件の数値が入っているとします。目標の値が含まれていれば true を、含まれていなければ false を残します。
○整数型の配列: data ← {10, 20, 30, 40, 50}
○整数型: i, 目標
○論理型: 見つかった
目標 ← 30
見つかった ← false
for (i を 1 から 5 まで 1 ずつ増やす)
if (data[i] = 目標)
見つかった ← true
endif
endfor
if (見つかった)
/* 目標の値が配列にあった場合の処理 */
endif
流れは三つに分かれています。ループの前で false を入れ、ループの中で条件が成立したら true にし、ループの後で結果を見ています。
ここで大事なのは、true を入れる代入がループの中にあり、判定はループの外にあるという配置です。この上下関係が崩れると、答えが変わります。
一行ずつ値を追ってみる¶
言葉だけでは動きがつかみにくいところでしょう。i が進むにつれてフラグがどう変わるかを表にします。
| i の値 | data[i] | data[i] = 目標 | 実行後の 見つかった |
|---|---|---|---|
| 開始前 | ― | ― | false |
| 1 | 10 | 偽 | false |
| 2 | 20 | 偽 | false |
| 3 | 30 | 真 | true |
| 4 | 40 | 偽 | true |
| 5 | 50 | 偽 | true |
i が3のところで true に変わり、その後は false に戻っていません。ここが最大の見どころです。
フラグは一度立てたら、自分で下ろさないかぎり立ったままです。だから4件目と5件目が一致しなくても、結果は true のまま保たれます。
この表を自分の手で書けるかどうかが、そのまま得点の差になります。書き方の手順に不安があれば、こちらの記事が助けになります。
【関連記事】擬似言語のトレース表の書き方|科目Bで変数の値を追う手順を解説
初期値を false にする理由¶
ループの前の 見つかった ← false は、省いてもよさそうに見えます。ところがこの一行こそ、フラグの要です。
初期値を入れないと、変数の中身が何なのか分からない状態でループに入ります。一件も一致しなかったとき、最後の if が何を見るのか決まりません。
まだ何も起きていないという状態を、はっきり false として置く。これが初期化の役割です。
もう一つ、初期化の位置にも注意してください。false を入れる行がループの中に入ってしまうと、毎回リセットされてしまいます。
その場合、最後の一件が一致したかどうかだけが残る処理になります。空欄補充の選択肢では、この位置違いがそのまま並んでいることがあります。
フラグで覚えるか、位置で覚えるか¶
探索の問題では、フラグの代わりに添字を使う書き方もよく出てきます。二つの違いを整理しておきましょう。
| 項目 | 論理型のフラグ | 整数型の位置 |
|---|---|---|
| 宣言 | 論理型: 見つかった | 整数型: 位置 |
| 初期値 | false | 0 や -1 |
| 一致したとき | true を代入 | そのときの i を代入 |
| 分かること | あったかどうかだけ | 何番目にあったか |
| 判定の書き方 | if (見つかった) | if (位置 > 0) |
見比べると、持っている情報の量が違うと分かります。位置を覚えておけば、あったかどうかも同時に判断できるわけです。
では位置だけ使えばよいかというと、そうとも限りません。何番目かに用がない処理では、フラグのほうが意図が読み取りやすくなります。
問題文がどちらを求めているかは、最後の判定を見れば分かります。位置を答えに使っているなら整数型、あるかないかだけを聞かれているなら論理型です。
探索そのものの流れを整理し直したい人は、こちらの記事と合わせて読むと、フラグの置き場所がはっきりします。
【関連記事】擬似言語の線形探索と二分探索の違いとは?科目Bで差がつく探索の読み方
見つかったら早く止めたいとき¶
先ほどのコードは、一致した後も最後まで回り続けます。無駄に感じた人もいるでしょう。
擬似言語の問題では、繰返しを途中で強制的に抜ける命令はまず出てきません。そのかわり、while の条件にフラグを混ぜて自然に終わらせます。
○整数型: i ← 1
○論理型: 見つかった ← false
while (i ≦ 5 and not 見つかった)
if (data[i] = 目標)
見つかった ← true
else
i ← i + 1
endif
endwhile
条件が二つ並んでいます。まだ範囲内で、かつまだ見つかっていない間だけ繰返す、という読み方です。
見つかった時点で not 見つかった が偽になり、次の判定でループが終わります。無駄な比較をしないぶん、処理が速くなります。
なお、この形では見つかったときに i を増やしていません。ループを抜けた後の i が、そのまま見つかった位置を表すからです。
繰返しの止まり方そのものがあやふやだと、この書き換えは追いにくくなります。for と while の使い分けを確認しておくと、読み違いがぐっと減ります。
【関連記事】擬似言語のwhileとforってどう違う?繰返し処理で迷子にならない方法を詳しく解説
多重ループとフラグの相性¶
フラグがいちばん活躍するのは、ループが二重になっている場面です。二次元配列から目的の値を探すような処理を思い浮かべてください。
内側のループで見つけても、外側のループはまだ回り続けます。内側だけを終わらせても、探索そのものは止まりません。
そこで、外側と内側の両方の条件にフラグを入れます。一つの変数で、二段構えの繰返しをまとめて止められるわけです。
書き方としては、どちらの while にも and not 見つかった を足すだけです。内側で true になれば、内側が終わった直後に外側の判定も偽になります。
このとき、行と列の添字を別々の変数で持っておくのを忘れないでください。抜けた後にその二つを見れば、何行目の何列目で見つかったかまで分かります。
入れ子の繰返しで添字が混乱しやすい人は、こちらで動きを整理してから戻ってくると理解が早いでしょう。
【関連記事】擬似言語の多重ループ(入れ子の繰返し)がわからない人へ|二重forの読み方を解説
何を表す旗なのかを言葉にする¶
多重ループに限らず、読むときのコツは共通しています。その変数が真のとき何が起きた状態なのかを、一言で言い換えることです。
見つかった なら、目標の値が一度でも現れた状態です。エラーあり なら、条件を満たさないデータが一件でも混ざっていた状態でしょう。
この言い換えができれば、初期値がどちらであるべきかも自然に決まります。まだ何も起きていないのだから false、という筋道です。
逆に、すべて条件を満たしているかどうかを調べるフラグは true で始めます。一件でも外れたら false にする、という組み立てになるからです。
Giji Academy の擬似言語シミュレーターなら、ループを一行ずつ進めながらフラグの値が切り替わる瞬間を目で追えます。初期化の位置を変えると結果が崩れることも、自分の手で試すと一度で納得できるはずです。
つまずきやすい場所を三つ¶
最後に、私が相談を受ける中で目立った間違いを挙げておきます。どれも一行の置き場所の差です。
一つ目は、初期化の位置です。ループの中で false に戻してしまうと、最後の一件の結果しか残りません。
二つ目は、判定の位置です。結果を見る if がループの中にあると、まだ全件を調べ終わっていない段階で判断してしまいます。
三つ目は、フラグを立てた後に値を戻してしまう書き方です。else の側で false を代入する形は、一致しなかった件が来るたびに旗を下ろします。
どれも、動かせば必ず結果に出る違いです。空欄補充の選択肢は、この三つの取り違えをそのまま並べてくることがあります。
似たような一行のずれで失点が続いている人は、確認の型を持っておくと安定します。こちらの記事も合わせて読んでみてください。
【関連記事】擬似言語でケアレスミスが多い人へ|よくある間違いと確認方法
まとめ¶
ここまでの内容を振り返ります。
フラグ変数は、繰返しの中で分かったことをループの外へ持ち出すための論理型の変数です。値は true と false の二つだけです。
基本の形は三段構えになります。ループの前で初期化し、ループの中で条件が成立したら値を変え、ループの後で結果を判定します。
初期値は、まだ何も起きていない状態を表す値にします。何かがあるかを調べるなら false から、すべてが満たされているかを調べるなら true から始めます。
途中で止めたいときは、while の条件に not を付けたフラグを加えます。多重ループでも、同じ一つのフラグで内側と外側をまとめて終わらせられます。
つまずきやすいのは、初期化の位置、判定の位置、値を戻してしまう書き方の三つでした。どれもトレース表を一枚書けば、その場で見抜けます。
真と偽しかない変数は、慣れてしまえばいちばん読みやすい部品です。今日の一問から、この旗は何が起きた印なのかを口に出して確かめてみてください。