擬似言語のトレース表の書き方|科目Bで変数の値を追う手順を解説
擬似言語のコードは読めるのに、なぜか答えが合わない。
一行ずつ追っているつもりなのに、途中で分からなくなっていませんか?
原因は、読む力ではないことがほとんどです。変数の値を、頭の中だけで覚えようとしていることに理由があります。
私はエンジニアとして10年以上、Webシステムの開発や運用に携わってきました。実務で不具合を追うときも、値がどう変わったかを一つずつ書き出して確かめます。
プロでも頭の中だけでは追いきれない、ということです。だから科目Bでも、書き出す技術そのものを身につけたほうが早いのです。
この記事では、トレース表という道具の作り方を、手順として最後まで説明します。
トレース表とは何か¶
トレース表は、プログラムを一行ずつ実行しながら、そのときの変数の値を書き並べた表のことです。特別な仕組みは何もありません。
紙に線を引いて、変数の名前を横に並べる。あとは処理が進むたびに、値を一行ずつ足していくだけです。
なぜ頭の中で追うと崩れるのか¶
人が同時に覚えていられる数は、思っているよりずっと少ないものです。変数が3つあって、ループが5回まわれば、値の更新は15回起こります。
その全部を記憶で保ちながら、次の行の意味も考える。これには無理があります。
科目Bで手が止まる瞬間の多くは、コードが読めないのではありません。sum がいくつだったか思い出せない、という状態です。
思い出す作業をやめれば、頭は読む作業だけに使えます。トレース表の目的は、そこにあります。
表にすると何が変わるか¶
一番大きいのは、間違いに気づけることです。値が紙に残っていれば、あとから見直して、どの行でおかしくなったかを特定できます。
頭の中の計算には、見直す場所がありません。だから、間違えたら最初からやり直すしかないのです。
書くと遅くなる、と感じるかもしれません。ですが実際には、書いた人のほうが速く正解にたどり着きます。
どんな問題で書くべきか¶
とはいえ、全ての問題で表を書く必要はありません。書くかどうかを決める目安があります。
変数の値が何度も上書きされる問題では、書いたほうが確実です。合計を求める処理や、最大値を探す処理がこれにあたります。
反対に、処理の流れを問うだけの問題なら、表は要りません。どの手続が呼ばれるか、という形の設問がそうです。
迷ったときは、値の上書きが3回以上あるかどうかで判断してみてください。それを超えると、記憶で追うのは急に苦しくなります。
トレース表の書き方を手順で覚える¶
やり方を毎回考えていると、本番で手が止まります。次の4つの手順として、体で覚えてしまいましょう。
まずは題材になるコードを見ておきます。配列の中から最大値を探す、よくある形の手続です。
○整数型: saidai(整数型の配列: data)
整数型: max ← data[1]
整数型: i
for (i を 2 から data の要素数 まで 1 ずつ増やす)
if (data[i] > max)
max ← data[i]
endif
endfor
return max
data が {3, 9, 4} の場合を追ってみます。ここから手順に沿って、表を組み立てていきます。
手順1:列に何を置くかを決める¶
最初に、追いかける変数を選びます。この手続なら i と max の2つで足ります。
宣言されている変数を全部書く必要はありません。値が変わるものだけに絞ります。
そして左端には、いま何周目なのかを書く列を作ってください。この列がないと、行の意味が読み取れなくなります。
手順2:処理が始まる前の行を作る¶
いきなりループから書き始めないでください。ループに入る直前の値を、最初の一行として残します。
この手続では、max に data[1] が入った状態、つまり 3 から始まります。ここを飛ばすと、何を基準に比べていたのかが分からなくなります。
手順3:一周ごとに一行だけ増やす¶
ループの中は、一周につき一行と決めておきます。行を増やしすぎると、かえって見づらくなるからです。
書くのは、その周が終わった時点の値です。途中の細かい変化まで書く必要はありません。
手順4:条件の結果も書き添える¶
分岐があるときは、条件が成り立ったかどうかを小さく書いておきます。ここが後から効いてきます。
実際に組み立てると、次のような形になります。
| 周 | i | data[i] | 条件 data[i] > max | max |
|---|---|---|---|---|
| 開始前 | ― | ― | ― | 3 |
| 1周目 | 2 | 9 | 成り立つ | 9 |
| 2周目 | 3 | 4 | 成り立たない | 9 |
答えは9です。表の右端をたどるだけで、値がどう動いたかが目で追えます。
条件の列があると、なぜ max が更新されなかったのかまで説明できます。ここが、値を並べただけの表との違いです。
繰返し処理そのものの形に不安が残る場合は、先にループの読み方を整理しておくと表が書きやすくなります。
【関連記事】擬似言語のwhileとforってどう違う?繰返し処理で迷子にならない方法を詳しく解説
分岐が入り組んだコードの追い方¶
条件分岐が重なると、表は急に書きにくくなります。どの枝を通ったのかが、値だけでは行に残らないからです。
たとえば、次のような多段の分岐を考えてみてください。
整数型: n ← 9
文字列型: kekka
if (n mod 15 = 0)
kekka ← FizzBuzz
elseif (n mod 3 = 0)
kekka ← Fizz
elseif (n mod 5 = 0)
kekka ← Buzz
else
kekka ← n を文字列にしたもの
endif
n が 9 のとき、上から順に判定されます。1つ目は成り立たず、2つ目で成り立つので、そこで分岐は終わりです。
大事なのは、3つ目の条件が確かめられないまま処理が抜けることです。ここを見落とすと、下の条件まで通った前提で表を作ってしまいます。
だから分岐のある問題では、通った枝の名前を一列だけ足します。elseif の1つ目、というように短く書けば十分です。
上から順に見て、成り立った時点で残りは飛ばす。この動きは、if が何段になっても変わりません。
逆に、if が並んで書かれていて elseif でつながっていない場合は、全ての条件が順番に判定されます。見た目が似ているので、endif の位置を指でたどって確かめてください。
通った行の番号を並べる書き方もある¶
コードの行に番号を振り、実行した順に番号を並べる方法もあります。処理が飛ぶ問題では、こちらのほうが分かりやすくなります。
この書き方は、途中で return する手続や、手続どうしが呼び合う問題で力を発揮します。値だけでなく、流れそのものが紙に残るからです。
条件分岐の読み方そのものでつまずいている場合は、先にそちらを固めるほうが近道です。
【関連記事】擬似言語のifで迷子になる人へ。擬似言語の条件分岐をスラスラ追う読み方
while のトレースは判定の場所に気をつける¶
for のトレースに慣れてきたら、次は while です。ここには、表の作り方に関わる落とし穴が一つあります。
回数があらかじめ決まっていない、という点です。何周するかは、条件を見るまで分かりません。
次のコードで確かめてみましょう。ある数を2で割り続けて、何回で1以下になるかを数える処理です。
整数型: n ← 25
整数型: kaisu ← 0
while (n > 1)
n ← n ÷ 2 /* 整数どうしの除算なので、小数は切り捨てる */
kaisu ← kaisu + 1
endwhile
while の表では、判定したときの値と、周が終わったあとの値を分けて書きます。この2つを同じ列にすると、必ず1行ずれます。
実際に並べてみます。最後に条件が成り立たなくなった行まで、きちんと残すのがコツです。
| 周 | 判定 n > 1 | 判定時の n | 周の終わりの n | kaisu |
|---|---|---|---|---|
| 開始前 | ― | ― | 25 | 0 |
| 1周目 | 成り立つ | 25 | 12 | 1 |
| 2周目 | 成り立つ | 12 | 6 | 2 |
| 3周目 | 成り立つ | 6 | 3 | 3 |
| 4周目 | 成り立つ | 3 | 1 | 4 |
| 終了 | 成り立たない | 1 | 1 | 4 |
答えは4回です。最後の行に注目してください。条件が成り立たなかったので、その周では n も kaisu も変わっていません。
最後の1行を書くかどうかで答えが変わる¶
初心者の表でよく抜けるのが、この終了の行です。4周目まで書いて、そこで手を止めてしまうのです。
すると、あと1周まわるのではないか、という迷いが残ります。成り立たなかったことを書いておけば、その迷いは消えます。
無限ループを疑うときも、この形が役に立ちます。判定に使う値が周ごとに変わっていなければ、そのループは止まりません。
本番では全部を書かない¶
科目Bは20問を100分で解く試験です。単純に割ると、1問あたり5分ほどしかありません。
その中で、全ての行をていねいに書き出す余裕はありません。だから、書く場所を選ぶ必要があります。
私が受験生に勧めているのは、次のような使い分けです。場面ごとに整理してみます。
| 場面 | 書き方 | 目安 |
|---|---|---|
| 空欄の直前まで | 表を書く | 変数2〜3列 |
| 空欄より後ろ | 書かない | 選択肢で確かめる |
| ループが長い問題 | 最初の2周だけ | 規則をつかむ |
| 手続を呼び合う問題 | 呼び出しの順に書く | 戻り値も列に入れる |
考え方は一つで、答えを出すのに必要な範囲だけ書く、という割り切りです。ループが20回まわる問題でも、20行書く必要はありません。
最初の2周を書けば、たいてい規則が見えてきます。3周目からは、その規則を使って一気に飛ばせます。
選択肢を使って表を短くする¶
空欄補充では、選択肢を先に見るのも有効です。候補が4つなら、それぞれを空欄に入れたときの1周目だけを比べれば足ります。
全ての候補を最後まで追う必要はありません。1周目で結果が分かれれば、その時点で絞り込めます。
時間配分そのものに悩んでいる場合は、読む速さを上げる工夫もあわせて確認してみてください。
【関連記事】基本情報技術者試験の科目Bで時間が足りない人へ|擬似言語問題を速く読むコツ
よくあるつまずきと直し方¶
トレース表を書き始めた人が最初にぶつかる壁は、だいたい決まっています。私が相談を受ける中で多いものを並べてみます。
| つまずき | 起きること | 直し方 |
|---|---|---|
| 初期値の行がない | 途中で基準を見失う | 開始前の行を必ず作る |
| 列が多すぎる | 書くのに時間がかかる | 値が変わる変数だけに絞る |
| 更新前と更新後が混ざる | 1行ずれた答えになる | 周の終わりの値に統一する |
| 添字と値を取り違える | まったく違う答えになる | data[i] の列を分けて置く |
一番多いのは、最後の行です。i そのものと data[i] は別の値なのに、同じ列にまとめてしまうのです。
添字は場所を表す番号で、data[i] はそこに入っている中身です。表の上では、必ず別の列に分けてください。
この一手間で、答えが一つずれる失点はかなり防げます。
配列の添字でつまずきやすい人は、そこを先に整理しておくと表の精度が上がります。
【関連記事】擬似言語の配列と添字がわからない人へ|要素数・二次元配列の読み方を解説
消しゴムを使わないほうがいい¶
書き間違えたとき、消して直したくなりますよね。ですが、間違えた値も残しておくほうが役に立ちます。
どこで勘違いしたかが見えるからです。私も仕事のメモでは、間違えた過程をあえて消さずに残しています。
手を動かして答え合わせをする¶
書いた表が合っているかどうかは、実際に動かしてみるのが一番確実です。
Giji Academy の擬似言語シミュレーターでは、コードを1行ずつ実行しながら、変数の中身がどう変わるかをその場で確認できます。自分で書いた表と見比べれば、どこでずれたのかがはっきりします。
最初のうちは、ずれて当たり前です。よかったら学習ページからのぞいてみてください。
まとめ¶
トレース表は、才能のある人だけが使う特別な技ではありません。覚えるのをやめて、書くことにするだけの、とても素朴な道具です。
手順もたった4つでした。追う変数を選び、開始前の行を作り、一周ごとに一行足し、条件の結果を書き添える。
そして本番では、必要な範囲だけを書く。ループが長ければ、最初の2周で規則をつかんで飛ばす。
最初は、書くこと自体に時間がかかると思います。それでも10問ほど手で追えば、書く速さも読む速さも変わってきます。
不思議なもので、表を書き慣れた人は、そのうち書かなくても値が追えるようになります。手で覚えた順番が、頭の中に残るからです。
つまりトレース表は、いつか卒業する道具です。ですがその日までは、遠慮なく紙を使ってください。
次に問題を開いたとき、まず余白に線を1本引いてみてください。そこから、擬似言語は少しずつ怖くなくなっていきます。