仮の宿 学習室

基本情報技術者 FUNDAMENTAL IT ENGINEER

プログラムの設計と読解

講義 3 本・確認問題 25 問 | 本試験では「科目B」(20問)の一部 | 最終更新 2026-09-24

この章で学ぶこと
目次
  1. 文字列とデータの加工
  2. オブジェクト指向の擬似言語
  3. 仕様から手続きを組み立てる
  4. 確認問題(25問)
  5. 演習ツール

1. 文字列とデータの加工

文字の並びや表(二次元配列)を1つずつ見ていって、数える・比べる・作り替える型が読めるようになります。

科目Bの擬似言語では、配列の要素番号(添字)が1から始まります。先頭が a[1] で、最後が a[aの要素数] です。多くのプログラミング言語が0から始まるので、ここを取り違えると答えがすべてずれます。まず「1から要素数まで」が全要素を1回ずつ見る書き方だと体に入れてください。for (i を 1 から aの要素数 まで 1 ずつ増やす) は、終わりの値である aの要素数 も含めて実行されます。逆に for (i を 1 から 0 まで 1 ずつ増やす) のように、始まりが終わりより大きいときは1回も実行されません。要素数が0の配列を渡したときにこの形になるので、空の配列の扱いを考えるときの手がかりになります。

文字列は、文字型の配列として扱われることがよくあります。s[1] が1文字目、s[sの要素数] が最後の文字です。文字どうしを比べるときは = と ≠ を使います(多くの言語で使う二重の等号は、擬似言語では使いません)。文字列をつなぐときは + を使います。文字の並びを1つずつ見ていく処理を走査(トラバース)といい、「特定の文字を数える」「最初に現れる位置を探す」「条件に合う文字だけを取り出す」といった処理は、すべてこの走査の上に作られています。

走査には型があります。1つ目は累算です。cnt ← 0 や sum ← 0 のように結果をためる変数を先に用意し、繰返しの中で少しずつ足していきます。この変数を累算変数といいます。初期値を何にするかが要注意で、合計なら0、積なら1、最大値なら「先頭の要素」にするのが安全です。最大値の初期値を0にしてしまうと、すべての要素が負のときに0という存在しない値を返してしまいます。2つ目は状態の記憶です。論理型の変数(フラグ)に「いま単語の途中かどうか」「まだ条件を満たしているか」を覚えさせ、繰返しの外で最終判断をします。3つ目は2本の添字です。先頭から進む i と末尾から戻る j を同時に動かし、i < j の間だけ繰り返せば、回文の判定や配列の反転が書けます。

回文とは、前から読んでも後ろから読んでも同じ並びのことです。s[i] と s[n - i + 1] が対になります。n - i + 1 という式は、i = 1 のとき n、i = n のとき 1 になる「折り返しの式」で、反転でも頻出します。反転を破壊的に行うときは、必ず作業用の変数を1つ用意して三角形に値を移します。tmp を使わずに a ← b、b ← a と書くと、1行目で a の元の値が消えてしまい、両方が b の値になります。これは科目Bで実際によく出るバグです。

数値と文字の変換もよく出ます。文字の "7" と数値の 7 は別物なので、そのままでは計算できません。数字の並びを数値にするときは、v ← v × 10 + その桁の数値 を先頭の桁から繰り返します。"2047" なら 0→2→20→204→2047 と育っていきます。逆に数値を文字にするときは、10 で割った余りを取り出して対応する文字に置き換え、商が0になるまで繰り返します(この場合は下の桁から出てくるので、最後に反転が要ります)。

二次元配列は表です。m[i][j] は i 行目 j 列目を指します。行数は mの要素数、i 行目の列数は m[i]の要素数 で表します。外側の繰返しで行を、内側の繰返しで列を回すのが基本形で、これを行優先の走査といいます。外と内を入れ替えれば列優先になります。行ごとの合計を出してから、その中の最大や最小を求めるといった二段構えの集計は定番です。このとき、行の集計用変数を内側の繰返しに入る直前で必ず初期化しないと、前の行の値が残って誤った結果になります。初期化の位置が繰返しの内か外かは、必ず行番号で確かめてください。

科目Bで頻出する走査の型(nは要素数)
型書き方の骨格初期値の決め方要素数0のときの動き
個数を数えるfor (i を 1 から n まで) の中で cnt ← cnt + 1cnt ← 0繰返しが実行されず0が返る
合計・平均sum ← sum + a[i]sum ← 0合計は0。平均は0除算になるので分岐が必要
最大・最小if (a[i] > mx) mx ← a[i]mx ← a[1](0にしない)a[1] が無いので事前の分岐が必要
探索(見つけたら終わり)if (a[i] = x) return i見つからないときの戻り値を決める繰返しが実行されず「なし」が返る
2本の添字(反転・回文)i ← 1、j ← n、while (i < j)i は先頭、j は末尾条件が成り立たず何もしない
二次元の集計外で行、内で列を回す行ごとの変数は内側に入る直前で初期化行が無いので初期値がそのまま残る
走査の3つの型(数える/2本の添字/二次元)
/* 例1: 文字型の配列 s の中の文字 c の個数を数える */○整数型: countChar(文字型の配列: s, 文字型: c)  整数型: i  整数型: cnt ← 0  for (i を 1 から sの要素数 まで 1 ずつ増やす)    if (s[i] = c)      cnt ← cnt + 1    endif  endfor  return cnt /* 例2: 2本の添字で配列を反転する(tmp が必須) */○reverse(文字型の配列: s)  整数型: i ← 1  整数型: j ← sの要素数  文字型: tmp  while (i < j)    tmp ← s[i]    s[i] ← s[j]    s[j] ← tmp    i ← i + 1    j ← j - 1  endwhile /* 例3: 二次元配列を行優先で走査して全体の合計を出す */○整数型: total(整数型の二次元配列: m)  整数型: i, j  整数型: s ← 0  for (i を 1 から mの要素数 まで 1 ずつ増やす)    for (j を 1 から m[i]の要素数 まで 1 ずつ増やす)      s ← s + m[i][j]    endfor  endfor  return s

用語

添字(そえじ)
配列の何番目かを表す番号。擬似言語では1から始まり、a[1] が先頭、a[aの要素数] が末尾。0から始まる言語の感覚のまま読むと、答えが1つずれる原因になる。
走査(トラバース)
配列や文字列の要素を先頭から末尾まで1つずつ順に見ていくこと。数える、探す、集計する、作り替えるといった処理は、ほとんどがこの走査を土台にして書かれている。
累算変数
繰返しの中で結果をためていく変数。合計なら0、積なら1、最大値なら先頭の要素で初期化するのが安全。初期値の選び方を誤ると、要素がすべて負のときなどに誤った値を返す。
フラグ変数
論理型の変数で、処理の途中の状態(見つかったか、単語の途中か など)を覚えておくために使う。繰返しの中で true や false を設定し、繰返しを抜けた後で最終判断をする。
回文
前から読んでも後ろから読んでも同じになる並び。s[i] と s[n - i + 1] を対にして比べる。要素数が0や1のときは比較が1回も起きず、定義上は回文として扱われる。
折り返しの式 n - i + 1
要素数 n の配列で、先頭から i 番目に対応する末尾からの位置を表す式。i が1のとき n、i が n のとき1になる。反転・回文・左右対称の判定でくり返し登場する。
二次元配列
行と列をもつ表の形のデータ。m[i][j] が i 行 j 列の要素。行数は mの要素数、i 行目の列数は m[i]の要素数 で表す。外側で行、内側で列を回すのが行優先の走査。
破壊的な入替え
配列の要素そのものを書き換えて並びを変えること。a[i] と a[j] を入れ替えるには作業用変数 tmp が必須で、tmp を使わないと片方の値が上書きされて消える。

例題

例題:s ← {"a", "b", "r", "a", "c", "a"} のとき、上の countChar(s, "a") はいくつを返すか。
答えと考え方 3。i を1から6まで動かし、s[1]、s[4]、s[6] が "a" と一致するので cnt が3回増える。要素数6の配列に対して繰返しは6回であり、5回でも7回でもないことを、繰返しの終わりが「6を含む」ことから確認しておく。
例題:反転の手続きで tmp を使わず、s[i] ← s[j]、s[j] ← s[i] と2行だけ書くとどうなるか。
答えと考え方 1行目で s[i] に s[j] の値が入り、s[i] の元の値は失われる。2行目の s[i] はすでに書き換わった値なので、s[j] にも同じ値が入り、両方が元の s[j] の値になってしまう。{a, b} を渡すと {b, b} になる。入替えには必ず作業用変数が要る。
例題:行ごとの合計を求めるとき、s ← 0 を外側の繰返しの外に置いてしまうと何が起こるか。
答えと考え方 1行目の合計に2行目の値が足し込まれ、行ごとの合計ではなく先頭からの累計になる。行ごとの値を出したいなら、s ← 0 は外側の繰返しに入った直後、内側の繰返しの手前に置く。初期化の位置は行番号で必ず確認する。

出典・根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類1:基礎理論 中分類2:アルゴリズムとプログラミング/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

2. オブジェクト指向の擬似言語

クラス定義の擬似言語を、メンバ変数・コンストラクタ・メソッド・継承の順に落ち着いて読めるようになります。

科目Bでは、手続きだけでなくクラスの形で書かれたプログラムも出ます。クラスとは、データ(メンバ変数)と、そのデータを扱う操作(メソッド)をひとまとめにした型の定義です。設計図にあたるものなので、それ自体は値を持ちません。設計図から実際に値をもつ実体を作ったものがインスタンス(オブジェクト)で、作る操作をインスタンス化といいます。1つのクラスから、値の違うインスタンスをいくつでも作れます。データと操作をまとめて外から中身を直接いじれないようにする考え方をカプセル化といい、外に見せる操作の入口をインタフェースといいます。

クラス定義の書き方は問題ごとに冒頭で説明されるので、その場で読み取るのが基本です。この教材では、クラス: クラス名 で定義を始め、その中に メンバ変数の宣言、クラス名と同じ名前の手続き(コンストラクタ)、そのほかの手続き(メソッド)を字下げして並べる形で書きます。コンストラクタはインスタンスを作るときに1回だけ自動で呼ばれる特別なメソッドで、メンバ変数に初期値を入れる役目を持ちます。戻り値の型は書きません。c ← Counter(10) と書けば、Counter のコンストラクタに10が渡され、できたインスタンスが c に入ります。

メソッドの中では、自分のインスタンスのメンバ変数を名前だけで参照できます。ただし引数の名前がメンバ変数と同じだと、どちらを指すのか分からなくなります。そこで「自分自身」を表す this を付けて this.price と書き、引数のほうは price と書いて区別します。this.price ← price は「メンバ変数の price に、引数の price の値を代入する」という意味で、逆ではありません。この向きを取り違えると、メンバ変数がいつまでも初期値のままになります。インスタンスのメソッドを外から呼ぶときは、c.add(5) のように インスタンス名.メソッド名(引数) と書きます。

変数にインスタンスを代入したときの動きにも注意が要ります。p ← Box(3) の後に q ← p と書くと、インスタンスがもう1つ複製されるのではなく、p と q が同じ1つのインスタンスを指すようになります。この状態で q.set(8) を呼ぶと、p から見た値も8に変わります。別の実体が欲しいなら、q ← Box(3) のようにもう一度コンストラクタを呼ばなければなりません。配列やインスタンスは参照として渡されるという前提は、科目Bの引っ掛けどころです。

継承は、既にあるクラスの性質を引き継いで新しいクラスを作る仕組みです。引き継がれる側をスーパクラス(親クラス)、引き継ぐ側をサブクラス(子クラス)といいます。サブクラスは、スーパクラスのメンバ変数とメソッドをそのまま使えるうえに、自分だけの追加もできます。スーパクラスと同じ名前・同じ引数のメソッドをサブクラスで定義し直すことを、オーバーライド(上書き)といいます。名前が同じでも引数の並びが違うものを用意するオーバーロード(多重定義)とは別物なので、混同しないでください。

オーバーライドがあると、同じ呼出しの書き方でも、実際に動くメソッドはインスタンスの本当のクラスによって決まります。これが多相性(ポリモーフィズム)です。スーパクラス Animal に show() があり、その中から name() を呼んでいるとき、サブクラス Dog のインスタンスに対して show() を呼ぶと、中の name() は Dog のほうが動きます。show() 自体は Dog で上書きしていなくても、呼ばれる name() は上書きされたものになるという点が要注意です。逆に、サブクラスで上書きしていないメソッドは、スーパクラスのものがそのまま使われます。Animal 型の配列に Animal と Dog と Cat を混ぜて入れ、同じ書き方で回すだけで、それぞれに応じた結果が並ぶのが多相性の効き目です。

クラス定義の擬似言語の読み方(本教材の表記)
書き方意味読むときの注意
クラス: CounterCounter という名前のクラス定義の始まりこの行より下の字下げ部分が中身
整数型: valueメンバ変数 value の宣言インスタンスごとに別の値を持つ
○Counter(整数型: v)コンストラクタクラスと同名。戻り値の型を書かない
○add(整数型: d)戻り値のないメソッド呼出しは インスタンス.add(5)
○整数型: get()整数型を返すメソッド○の後ろが戻り値の型
this.value ← valueメンバ変数に引数を代入左がメンバ変数、右が引数。向きに注意
c ← Counter(10)インスタンス化コンストラクタに10が渡される
クラス: Dog(Animal を継承する)Dog は Animal のサブクラス同名メソッドを書けばオーバーライド
クラス定義・コンストラクタ・this・継承とオーバーライド
クラス: Counter  /* メンバ変数 */  整数型: value  /* コンストラクタ(クラスと同名・戻り値の型を書かない) */  ○Counter(整数型: value)    this.value ← value  /* メソッド */  ○add(整数型: d)    value ← value + d  ○整数型: get()    return value クラス: TwiceCounter(Counter を継承する)  ○TwiceCounter(整数型: value)    this.value ← value  /* add を上書きする(オーバーライド) */  ○add(整数型: d)    value ← value + d × 2 ○整数型: main()  Counter: a  TwiceCounter: b  a ← Counter(10)  b ← TwiceCounter(10)  a.add(3)  b.add(3)  return a.get() + b.get()

用語

クラス
データ(メンバ変数)と操作(メソッド)をひとまとめにした型の定義。設計図にあたり、それ自体は値を持たない。同じクラスから値の異なるインスタンスをいくつでも作れる。
インスタンス(オブジェクト)
クラスから作られた、実際に値をもつ実体。作る操作をインスタンス化という。同じクラスの別インスタンスどうしは、メンバ変数の値を独立に持つ。
メンバ変数
クラスが持つデータを入れる変数。インスタンスごとに別の値を保持する。メソッドの中からは名前だけで参照でき、引数と名前が重なるときは this を付けて区別する。
コンストラクタ
インスタンスを作るときに1回だけ自動で呼ばれる特別なメソッド。クラスと同じ名前で、戻り値の型を書かない。メンバ変数に初期値を設定するのが主な役目。
this(自分自身)
メソッドの中で、そのメソッドが動いているインスタンス自身を指す書き方。this.x ← x は「メンバ変数 x に引数 x の値を入れる」意味で、代入の向きを逆に読まないよう注意する。
継承
既存のクラス(スーパクラス)の性質を引き継いで新しいクラス(サブクラス)を作る仕組み。共通部分を親にまとめられるので、同じ記述の重複を減らせる。
オーバーライド(上書き)
スーパクラスと同じ名前・同じ引数のメソッドを、サブクラスで定義し直すこと。呼び出したときはサブクラスのほうが動く。引数の並びを変えて別に定義するオーバーロードとは異なる。
多相性(ポリモーフィズム)
同じ呼出しの書き方でも、インスタンスの実際のクラスに応じて動くメソッドが変わる性質。スーパクラス型の配列に子クラスを混ぜても、同一の記述でそれぞれの動作をさせられる。
カプセル化
データと、それを扱う操作を1つにまとめ、外部からはメソッドを通じてしか触れないようにすること。内部の作りを変えても外側に影響が出にくくなる。

例題

例題:上の main() の戻り値はいくつか。
答えと考え方 29。a は Counter なので add(3) で 10 + 3 = 13。b は TwiceCounter で add が上書きされているので 10 + 3 × 2 = 16。get() は上書きしていないので Counter のものがそのまま使われ、16 を返す。13 + 16 = 29 になる。
例題:5行目の ○Counter(整数型: value) の中で、this を付けずに value ← value と書くとどうなるか。
答えと考え方 左右とも引数の value を指すことになり、メンバ変数には何も入らない。メンバ変数は初期値のまま(未定義の値)で残る。名前が重なるときに、どちらを指すのかをはっきりさせるのが this の役目である。
例題:p ← Counter(5) の後に q ← p と書き、q.add(1) を呼んだとき、p.get() は何を返すか。
答えと考え方 6を返す。q ← p はインスタンスの複製ではなく、p と q が同じ1つのインスタンスを指す状態になる。したがって q への操作は p からも見える。別の実体が欲しければ q ← Counter(5) のようにコンストラクタをもう一度呼ぶ必要がある。

出典・根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類4:開発技術 中分類12:システム開発技術(オブジェクト指向設計)/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

3. 仕様から手続きを組み立てる

仕様どおりに動くかを机上で確かめ、境界と計算量を押さえ、バグの位置を突き止める手順が身につきます。

科目Bの問題文には、たいてい「この手続きは何をするものか」という仕様が日本語で書かれています。まずこの仕様を、入力・出力・前提条件の3つに分けて書き出してください。入力は引数の型と意味、出力は戻り値の型と意味、前提条件は「要素数は1以上とする」「配列は昇順に整列済みとする」といった、成り立っていることにしてよい条件です。前提条件が書かれていない部分は、こちらで守らなければならない部分です。たとえば「要素数が0のときは0を返す」と仕様に書いてあるのに、手続きにその分岐が無ければ、それだけで仕様違反になります。

次に、実際に値を入れて手で動かします。これをトレースといいます。おすすめは表を作る方法です。左端に行番号または繰返しの回数、その右に変数を1列ずつ並べ、値が変わったところだけ書き込みます。頭の中だけで追うと必ずどこかで取り違えるので、面倒でも書くほうが速くて確実です。トレースする値の選び方にはこつがあり、答えが一目で分かる小さな入力(要素数3程度)と、境界の入力の2種類を用意します。

境界とは、動きが切り替わる境目のことです。科目Bで問われる境界はだいたい決まっています。要素数が0のとき、要素数が1のとき、探しているものが先頭にあるとき、末尾にあるとき、まったく無いとき、同じ値が複数あるとき、値がすべて負のとき、の7つです。要素数が0なら for (i を 1 から 0 まで 1 ずつ増やす) となって繰返しは1回も実行されず、累算変数の初期値がそのまま返ります。合計なら0で正しくても、平均なら0による除算になって破綻します。要素数が1なら、隣どうしを比べる繰返し(1 から n - 1 まで)はやはり0回です。探しているものが先頭にあるときは、繰返しの1回目で return できるか、末尾にあるときは最後の要素まで届くかを確かめます。同じ最大値が複数あるときは、比較に > を使うか ≧ を使うかで「最初の位置」か「最後の位置」かが変わります。この1文字が正解と誤答を分けます。

計算量は、入力の大きさ n が増えたときに手間がどう増えるかの見積りです。繰返しが1重なら n に比例して O(n)、二重で内側が n 回なら O(n^2)、二重でも内側が i + 1 から n までなら回数は n(n - 1) / 2 なので、やはり O(n^2) です。半分ずつ候補を捨てていく二分探索は O(log n) で、要素数1000なら最悪10回の比較で終わります(2の9乗が512、2の10乗が1024なので、1024以下なら10回で足りる)。整列は、単純な交換法(バブルソート)や選択法・挿入法が O(n^2)、クイックソートやマージソート、ヒープソートが平均 O(n log n) です。定数倍は無視して、n が大きくなったときの増え方だけを見るのが計算量の考え方です。

バグを直すときは、当てずっぽうに書き換えず、位置を絞ってから直します。手順は3段階です。1つ目は、仕様どおりの結果と実際の結果が食い違う最小の入力を見つけること。2つ目は、その入力でトレースし、変数の値が初めておかしくなる行を特定すること。3つ目は、その行だけを仕様に照らして直すことです。頻出のバグは型が決まっていて、添字の1ずれ(n と n - 1、i と i + 1 の取り違え)、初期化の位置ずれ(内側の繰返しに入る前で初期化すべき変数を外に置いた)、最大値の初期値を0にした、入替えで作業用変数を使わなかった、境界の分岐が抜けている、比較演算子の > と ≧ の取り違え、の6つです。選択肢に行番号が書いてあるときは、必ずその行を目で追って、書いてあるとおりの記述かどうかを先に確かめてください。

境界のチェックリストと、そこで起きやすい不具合
境界そこで何が起きるか確かめ方
要素数が0for (i を 1 から 0 まで) となり繰返しが0回。初期値がそのまま返る合計は0で正しいが、平均は0除算、最大値はa[1]の参照で破綻する
要素数が1隣どうしを比べる 1 から n - 1 までの繰返しが0回戻り値が初期値のままでよいかを仕様と照合する
目的の値が先頭繰返しの1回目で見つかる初期値やループ前の処理を飛ばしていないか
目的の値が末尾繰返しの最終回で見つかる終わりが n か n - 1 か。1つ手前で止まっていないか
該当なし繰返しを抜けた後の処理に進む見つからないときの戻り値が仕様どおりか
同じ最大値が複数> なら最初の位置、≧ なら最後の位置になる仕様がどちらを求めているかを読む
すべて負の値最大値の初期値を0にすると、存在しない0を返す初期値を a[1] にしているか
二分探索の本体とトレース表、そして要素数0の境界
/* 仕様: 昇順に整列済みの配列 a から値 x を二分探索する。 *//*       見つかればその添字、見つからなければ0を返す。   */○整数型: bsearch(整数型の配列: a, 整数型: x)  整数型: lo ← 1  整数型: hi ← aの要素数  整数型: mid  while (lo ≦ hi)    mid ← (lo + hi) ÷ 2 の商    if (a[mid] = x)      return mid    elseif (a[mid] < x)      lo ← mid + 1    else      hi ← mid - 1    endif  endwhile  return 0 a ← {2, 5, 8, 11, 14, 17, 20}、x ← 17 のトレース  回  lo  hi  mid  a[mid]  判定  1    1   7    4     11    11 < 17 なので lo ← 5  2    5   7    6     17    一致するので 6 を返す 境界: aの要素数 が0のとき lo ← 1、hi ← 0 となり、      7行目の lo ≦ hi が最初から成り立たないので0が返る

用語

仕様
その手続きが何を受け取り、何を返し、どんな条件のもとで動くかを定めたもの。入力・出力・前提条件の3つに分けて読むと、確かめるべき点がはっきりする。
トレース(机上実行)
実際に値を入れて、プログラムを1行ずつ手で追いかけること。行番号と変数を表にして、値が変わったところだけ書き込むと、取り違えが起きにくい。
境界値
動きが切り替わる境目の入力。要素数0、要素数1、先頭・末尾に目的の値がある場合、該当なし、同じ値が複数ある場合などが代表例で、バグはここに集中する。
0による除算
0で割ろうとして処理が破綻すること。合計を要素数で割って平均を出す手続きでは、要素数が0のときに起きるため、割る前に要素数を調べる分岐が必要になる。
添字の1ずれ
n と n - 1、i と i + 1 のように、繰返しの範囲や参照位置が1つずれるバグ。末尾の要素を見落とす、または範囲外を参照する形で表れる。境界の入力で見つかりやすい。
計算量
入力の大きさ n に対して処理の手間がどう増えるかの見積り。1重の繰返しは O(n)、二重は O(n^2)、半分ずつ絞る二分探索は O(log n)。定数倍は無視して増え方だけを見る。
二分探索
昇順に整列済みの配列で、真ん中と比べて候補を半分ずつ捨てていく探索。1回の比較で候補が半減するので、要素数 n に対し最悪でも約 log2(n) 回の比較で終わる。
参照渡し
配列やインスタンスを引数として渡すとき、値の複製ではなく実体そのものを指す情報が渡されること。呼ばれた側で書き換えると、呼んだ側の配列も変わる。

例題

例題:要素数1000の整列済み配列に対して二分探索を行うと、最悪で何回の比較が必要か。
答えと考え方 10回。1回の比較で候補が半分以下になるので、1000→500→250→125→62→31→15→7→3→1→0 と10回で候補が尽きる。2の9乗が512で1000に足りず、2の10乗が1024で1000を超えるため、最悪10回という見方でもよい。線形探索なら最悪1000回である。
例題:「配列の最大値をもつ要素のうち最も前にあるものの添字を返す」仕様で、比較に ≧ を使うと何が起こるか。
答えと考え方 同じ最大値が複数あるとき、後ろの要素でも条件が成り立って添字が更新され続けるため、最も後ろの位置を返してしまう。{4, 7, 7, 2} なら仕様上の答えは2だが3が返る。最も前を返したいなら > を使う。逆に最も後ろを返す仕様なら ≧ が正しい。
例題:二重の繰返しで、外側が i を 1 から n - 1、内側が j を i + 1 から n まで回るとき、内側の本体は何回実行されるか。
答えと考え方 n(n - 1) / 2 回。i = 1 のとき n - 1 回、i = 2 のとき n - 2 回…と減っていく和になる。n = 100 なら 100 × 99 ÷ 2 = 4950 回である。二重の繰返しでも n^2 回ではないが、n が大きくなったときの増え方は n^2 に比例するので、計算量は O(n^2) と表す。

出典・根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類1:基礎理論 中分類2:アルゴリズムとプログラミング(アルゴリズムの設計・計算量)/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

確認問題(25問)

四肢択一。「正解と解説」を開くと、正解の理由と他の選択肢が違う理由を確認できます。

問1|文字を数える

次の手続き countChar を、文字型の配列 s ← {"a", "b", "r", "a", "c", "a"} と文字 c ← "a" を引数として呼び出したとき、戻り値はどれか。ここで、配列の要素番号は1から始まる。

文字型の配列の走査
/* 文字型の配列 s の中にある文字 c の個数を返す */○整数型: countChar(文字型の配列: s, 文字型: c)  整数型: i  整数型: cnt ← 0  for (i を 1 から sの要素数 まで 1 ずつ増やす)    if (s[i] = c)      cnt ← cnt + 1    endif  endfor  return cnt
  1. 2
  2. 3
  3. 4
  4. 6
正解と解説
正解:B. 3

5行目の繰返しは i を1から6(sの要素数)まで動かし、終わりの6も含めて6回実行される。s[1]、s[4]、s[6] が "a" と一致するので cnt は3回増え、戻り値は3。2は s[6] の一致を数え落とした場合、4は "a" 以外も数えた場合、6は要素数そのもので、一致判定を無視した値である。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類1:基礎理論 中分類2:アルゴリズムとプログラミング/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問2|回文の判定

次の手続き check の説明として、最も適切なものはどれか。ここで、配列の要素番号は1から始まる。

2本の添字で挟み込む判定
○論理型: check(文字型の配列: s)  整数型: i ← 1  整数型: j ← sの要素数  while (i < j)    if (s[i] ≠ s[j])      return false    endif    i ← i + 1    j ← j - 1  endwhile  return true
  1. 配列 s の要素がすべて同じ値のとき true を返す
  2. 配列 s を先頭から読んだ並びと、末尾から読んだ並びが同じとき true を返す
  3. 配列 s の要素が昇順に並んでいるとき true を返す
  4. 配列 s に同じ値の要素が二つ以上ないとき true を返す
正解と解説
正解:B. 配列 s を先頭から読んだ並びと、末尾から読んだ並びが同じとき true を返す

i は先頭から、j は末尾から中央へ向かって進み、対になる s[i] と s[j] が違えば直ちに false を返す。最後まで違いがなければ true なので、回文(前から読んでも後ろから読んでも同じ並び)の判定である。すべて同じ値でなくても {"a","b","a"} は true なので選択肢1は誤り。{"a","b","c"} は昇順だが false なので昇順の判定でもない。{"a","b","b","a"} は重複があるのに true なので、重複の有無の判定でもない。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類1:基礎理論 中分類2:アルゴリズムとプログラミング/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問3|空の配列

次の手続き reverse に、要素数が0の配列と、要素数が1の配列をそれぞれ渡したときの動作の説明として、正しいものはどれか。ここで、配列は参照渡しとする。

配列の反転(要素数0・1の扱いに注目)
○reverse(文字型の配列: s)  整数型: i ← 1  整数型: j ← sの要素数  文字型: tmp  while (i < j)    tmp ← s[i]    s[i] ← s[j]    s[j] ← tmp    i ← i + 1    j ← j - 1  endwhile
  1. 要素数が0のときは6行目で s[1] を参照して誤りになり、要素数が1のときは配列を変えずに終わる
  2. 要素数が0のときは配列を変えずに終わるが、要素数が1のときは無限ループになる
  3. 要素数が0のときも1のときも、5行目の条件が最初から成り立たず、配列を変えずに終わる
  4. 要素数が0のときも1のときも、6行目から8行目が1回だけ実行される
正解と解説
正解:C. 要素数が0のときも1のときも、5行目の条件が最初から成り立たず、配列を変えずに終わる

要素数が0なら i ← 1、j ← 0 となり、5行目の i < j は 1 < 0 で成り立たない。要素数が1なら i ← 1、j ← 1 で 1 < 1 も成り立たない。どちらも繰返しの中に一度も入らないので、6行目以降は実行されず、s[1] の参照も起きない。よって配列はそのままで終わる。無限ループにもならず、入替えが1回起きることもない。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類1:基礎理論 中分類2:アルゴリズムとプログラミング/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問4|部分列の探索

次の手続き find は、文字型の配列 s の中に配列 p と同じ並びが現れる最初の位置(先頭の要素番号)を返し、現れなければ -1 を返す。7行目の空欄に入れる式はどれか。ここで、pの要素数 は sの要素数 以下とする。

部分列の探索(7行目が空欄)
○整数型: find(文字型の配列: s, 文字型の配列: p)  整数型: i, j  論理型: ok  for (i を 1 から sの要素数 - pの要素数 + 1 まで 1 ずつ増やす)    ok ← true    for (j を 1 から pの要素数 まで 1 ずつ増やす)      if (s[     ] ≠ p[j])        ok ← false      endif    endfor    if (ok)      return i    endif  endfor  return -1
  1. i + j - 1
  2. i + j
  3. i + j + 1
  4. j - i + 1
正解と解説
正解:A. i + j - 1

外側の i は照合を始める s の位置、内側の j は p の中の位置である。i の位置に p の1文字目を合わせるので、p[j] と比べる相手は s[i + j - 1] になる(j = 1 のとき s[i])。s ← {"a","b","c","a","b","d"}、p ← {"a","b","d"} で試すと、i + j - 1 は正しく4を返すが、i + j は1つ後ろとずれて3を返し、i + j + 1 は2を返す。j - i + 1 は i が2以上で要素番号が0以下になり、参照できない。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類1:基礎理論 中分類2:アルゴリズムとプログラミング/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問5|行の最大値

次の手続き f を、二次元配列 m ← {{3, 8, 2}, {9, 1, 4}, {5, 6, 7}} を引数として呼び出したとき、戻り値はどれか。ここで、m[i][j] は i 行 j 列の要素を表し、要素番号は1から始まる。

二次元配列の二段構えの集計
○整数型: f(整数型の二次元配列: m)  整数型: i, j  整数型: rowMax  整数型: ans  ans ← 0  for (i を 1 から mの要素数 まで 1 ずつ増やす)    rowMax ← m[i][1]    for (j を 2 から m[i]の要素数 まで 1 ずつ増やす)      if (m[i][j] > rowMax)        rowMax ← m[i][j]      endif    endfor    if (i = 1)      ans ← rowMax    elseif (rowMax < ans)      ans ← rowMax    endif  endfor  return ans
  1. 3
  2. 8
  3. 9
  4. 7
正解と解説
正解:D. 7

内側の繰返しで各行の最大値を求めると、m[1] は8、m[2] は9、m[3] は7になる。13行目から17行目でその中の最小を残すので、8→8、9は8より大きいので更新なし、7は8より小さいので更新され、戻り値は7になる。8は m[1] の最大値だけを見た値、9は全体の最大値、3は m[1][1] の値にすぎず、いずれもこの手続きの戻り値ではない。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類1:基礎理論 中分類2:アルゴリズムとプログラミング/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問6|数字と数値

次の手続き toNumber の説明として、最も適切なものはどれか。ここで、引数 s には "0" から "9" までの文字だけが入っているものとする。

数字の文字列を数値に変換する
○整数型: toNumber(文字型の配列: s)  整数型: i  整数型: k  整数型: v ← 0  文字型の配列: d  d ← {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}  for (i を 1 から sの要素数 まで 1 ずつ増やす)    for (k を 1 から 10 まで 1 ずつ増やす)      if (s[i] = d[k])        v ← v × 10 + (k - 1)      endif    endfor  endfor  return v
  1. s の各文字が表す数字の値を合計した結果を返す
  2. s が表す10進数の値を返す
  3. s を末尾から先頭に向かって読んだ10進数の値を返す
  4. s に含まれる文字の個数を返す
正解と解説
正解:B. s が表す10進数の値を返す

6行目の配列 d は k 番目に数字 k - 1 の文字が入っている。10行目で v ← v × 10 + (k - 1) を先頭の文字から繰り返すので、桁が1つずつ上がっていく。s ← {"2","0","4","7"} なら 0→2→20→204→2047 となり、2047 を返す。各桁の値の合計なら13、末尾から読めば7402、文字数なら4であり、いずれも一致しない。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類1:基礎理論 中分類2:アルゴリズムとプログラミング/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問7|最大値の位置

次の手続き maxPos は、1行目から3行目の仕様どおりに動かない場合がある。その原因はどれか。

最大値の位置を返す手続き(仕様は1〜3行目)
/* 仕様: 配列 a の中で最大の値をもつ要素のうち、 *//*       最も前にあるものの添字を返す。         *//*       a の要素数は 1 以上とする。            */○整数型: maxPos(整数型の配列: a)  整数型: i  整数型: p  p ← 1  for (i を 2 から aの要素数 まで 1 ずつ増やす)    if (a[i] ≧ a[p])      p ← i    endif  endfor  return p
  1. 7行目で p の初期値を1にしていること。0にしなければならない
  2. 8行目の繰返しが i = 2 から始まっていること。1から始めなければならない
  3. 9行目の比較に ≧ を使っていること。同じ最大値が複数あると、より後ろの添字に更新されてしまう
  4. 13行目の return が繰返しの外にあること。if の中で return しなければならない
正解と解説
正解:C. 9行目の比較に ≧ を使っていること。同じ最大値が複数あると、より後ろの添字に更新されてしまう

a ← {4, 7, 7, 2} を渡すと、i = 3 のとき a[3] ≧ a[2] が 7 ≧ 7 で成り立ち、p が3に更新される。仕様は「最も前にあるもの」なので2が正しく、比較を > にすれば更新されず2が返る。p の初期値1は先頭を指すので正しい。i を1から回すと a[1] と自分自身を比べるだけで結果は変わらない。return は全要素を見終えてから行う必要があり、繰返しの外にあるのが正しい。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類1:基礎理論 中分類2:アルゴリズムとプログラミング/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問8|単語の区切り

次の手続き countWords の説明として、最も適切なものはどれか。ここで、引数 s には英字と半角空白だけが入っているものとする。

フラグ変数で単語の切れ目を見つける
○整数型: countWords(文字型の配列: s)  整数型: i  整数型: cnt ← 0  論理型: inWord ← false  for (i を 1 から sの要素数 まで 1 ずつ増やす)    if (s[i] = " ")      inWord ← false    else      if (not inWord)        cnt ← cnt + 1        inWord ← true      endif    endif  endfor  return cnt
  1. s に含まれる、空白でない文字の個数を数える
  2. s に含まれる空白の個数を数える
  3. s の中の、空白で区切られたひとまとまりの文字列(単語)の個数を数える
  4. s の中の、連続して並ぶ空白のまとまりの個数を数える
正解と解説
正解:C. s の中の、空白で区切られたひとまとまりの文字列(単語)の個数を数える

inWord は「いま単語の中にいるか」を覚えるフラグである。空白でない文字に出会ったとき、直前が単語の外だった場合にだけ cnt を増やすので、単語の先頭を1回ずつ数えることになる。s ← {"a"," ","b","c"," "," ","d"} なら単語は "a"、"bc"、"d" の3個で戻り値も3。空白でない文字は4個、空白は3個、連続する空白のまとまりは2個であり、どれも3にはならない。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類1:基礎理論 中分類2:アルゴリズムとプログラミング/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問9|重複の除去

次の手続き uniqueCount を、整数型の配列 a ← {3, 1, 3, 5, 1, 3} を引数として呼び出したとき、戻り値はどれか。

自分より前を調べて重複を除く
○整数型: uniqueCount(整数型の配列: a)  整数型: i, j  整数型: cnt ← 0  論理型: dup  for (i を 1 から aの要素数 まで 1 ずつ増やす)    dup ← false    for (j を 1 から i - 1 まで 1 ずつ増やす)      if (a[j] = a[i])        dup ← true      endif    endfor    if (not dup)      cnt ← cnt + 1    endif  endfor  return cnt
  1. 3
  2. 4
  3. 5
  4. 6
正解と解説
正解:A. 3

内側の繰返しは、いま見ている a[i] と同じ値が自分より前にあるかを調べる。i = 1 のときは「1 から 0 まで」となり1回も実行されないので、必ず dup が false のままで数えられる。前に同じ値が無いのは a[1] の3、a[2] の1、a[4] の5の3個なので、戻り値は3、すなわち異なる値の種類数である。6は要素数そのもの、4や5は重複の数え漏れである。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類1:基礎理論 中分類2:アルゴリズムとプログラミング/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問10|クラスの実行

次のプログラムで、main() の戻り値はどれか。ここで、クラス: の行はクラス定義の始まりを表し、クラスと同じ名前で戻り値の型のない手続きはコンストラクタを表す。

クラス定義とインスタンスの操作
クラス: Counter  整数型: value  ○Counter(整数型: v)    value ← v  ○add(整数型: d)    value ← value + d  ○整数型: get()    return value ○整数型: main()  Counter: c  c ← Counter(10)  c.add(5)  c.add(-2)  return c.get()
  1. 3
  2. 10
  3. 15
  4. 13
正解と解説
正解:D. 13

12行目でコンストラクタ Counter(10) が呼ばれ、メンバ変数 value に10が入る。13行目の c.add(5) で15、14行目の c.add(-2) で13になる。15行目の c.get() はそのときの value を返すので13である。10はコンストラクタ直後の値、15は1回目の add までの値、3は加えた分だけを合計した値であり、いずれも最終的な value ではない。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類4:開発技術 中分類12:システム開発技術(オブジェクト指向設計)/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問11|thisの意味

次のプログラムの5行目 this.price ← price の意味として、正しいものはどれか。

引数と同名のメンバ変数を this で区別する
クラス: Item  整数型: price  整数型: count  ○Item(整数型: price, 整数型: count)    this.price ← price    this.count ← count  ○整数型: total()    return this.price × this.count ○整数型: main()  Item: a  Item: b  a ← Item(120, 3)  b ← Item(80, 5)  return a.total() + b.total()
  1. 引数 price に、メンバ変数 price の値を代入する
  2. メンバ変数 price に、引数 price の値を代入する
  3. メンバ変数 price と引数 price の値を入れ替える
  4. メンバ変数 price を未定義の値に戻す
正解と解説
正解:B. メンバ変数 price に、引数 price の値を代入する

this は、そのメソッドが動いているインスタンス自身を指す。コンストラクタの引数名がメンバ変数名と同じなので、this を付けた側がメンバ変数、付けない側が引数になる。代入は右から左なので、引数の値がメンバ変数に入る。向きが逆なら引数だけが書き換わってメンバ変数は未定義のままになり、8行目の total() が正しく計算できない。入れ替えでも初期化の取消しでもない。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類4:開発技術 中分類12:システム開発技術(オブジェクト指向設計)/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問12|参照の代入

次のプログラムで、main() の戻り値はどれか。ここで、クラスの変数への代入は、インスタンスを複製せずに同じインスタンスを指すようにするものとする。

インスタンスを指す変数どうしの代入
クラス: Box  整数型: n  ○Box(整数型: v)    n ← v  ○set(整数型: v)    n ← v  ○整数型: get()    return n ○整数型: main()  Box: p  Box: q  p ← Box(3)  q ← p  q.set(8)  return p.get() + q.get()
  1. 16
  2. 11
  3. 8
  4. 3
正解と解説
正解:A. 16

13行目で n が3のインスタンスが作られ p が指す。14行目の q ← p は複製ではないので、p と q は同じ1つのインスタンスを指す。15行目の q.set(8) でそのインスタンスの n が8になり、p.get() も q.get() も8を返すため合計は16になる。11は複製されて p が3のままだった場合、8や3は片方だけを数えた値である。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類4:開発技術 中分類12:システム開発技術(オブジェクト指向設計)/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問13|継承と上書き

次のプログラムで、main() の戻り値はどれか。ここで、(Animal を継承する)はスーパクラスが Animal であることを表す。

オーバーライドされたメソッドの呼ばれ方
クラス: Animal  ○Animal()    /* 何もしない */  ○文字列型: name()    return "動物"  ○文字列型: cry()    return "…"  ○文字列型: show()    return name() + "は" + cry() + "と鳴く" クラス: Dog(Animal を継承する)  ○Dog()    /* 何もしない */  ○文字列型: name()    return "犬"  ○文字列型: cry()    return "ワン" ○文字列型: main()  Dog: d  d ← Dog()  return d.show()
  1. 動物は…と鳴く
  2. 動物はワンと鳴く
  3. 犬はワンと鳴く
  4. 犬は…と鳴く
正解と解説
正解:C. 犬はワンと鳴く

d は Dog のインスタンスなので、d.show() は Dog で上書きしていない Animal の show() が動く。しかしその中の name() と cry() は、実際のクラスである Dog のもの(14行目と16行目)が呼ばれる。したがって "犬" と "ワン" が使われ、"犬はワンと鳴く" になる。show() の中だから Animal 側の name()・cry() が使われる、と読むと "動物は…と鳴く" などになるが、これが多相性の効くところである。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類4:開発技術 中分類12:システム開発技術(オブジェクト指向設計)/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問14|多相性

次のプログラムで、main() の戻り値はどれか。ここで、Animal の配列には Animal とそのサブクラスのインスタンスを入れられるものとし、引数のないコンストラクタは各クラスに用意されているものとする。

スーパクラス型の配列に子を混ぜて回す
クラス: Animal  ○文字列型: name()    return "動物"  ○文字列型: cry()    return "…" クラス: Dog(Animal を継承する)  ○文字列型: name()    return "犬"  ○文字列型: cry()    return "ワン" クラス: Cat(Animal を継承する)  ○文字列型: name()    return "猫" ○文字列型: main()  Animal の配列: zoo  整数型: i  文字列型: r ← ""  zoo ← {Animal(), Dog(), Cat()}  for (i を 1 から zooの要素数 まで 1 ずつ増やす)    r ← r + zoo[i].cry()  endfor  return r
  1. ………
  2. …ワン…
  3. …ワンワン
  4. ワンワンワン
正解と解説
正解:B. …ワン…

Animal の cry() は "…" を返す。Dog は cry() を上書きして "ワン" を返すが、Cat は name() だけを上書きし cry() は上書きしていないので、Animal の cry() がそのまま使われて "…" を返す。配列の順に Animal、Dog、Cat と呼ばれるので "…"+"ワン"+"…" となり "…ワン…" になる。Cat も上書きしていると考えると "…ワンワン"、上書きを無視すると "………" になるが、いずれも誤りである。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類4:開発技術 中分類12:システム開発技術(オブジェクト指向設計)/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問15|クラスと実体

オブジェクト指向における、クラスとインスタンス(オブジェクト)の関係の説明として、最も適切なものはどれか。

  1. インスタンスはクラスの一種であり、インスタンスから新しいクラスを作ることをインスタンス化という
  2. クラスは実行時にメモリ上に作られる実体であり、インスタンスはその設計図にあたる定義である
  3. 1つのクラスから作れるインスタンスは1つだけであり、複数必要なときは継承して別のクラスを作る
  4. クラスはデータ(メンバ変数)と操作(メソッド)をまとめた型の定義であり、そこから実際に値をもつ実体として作られたものがインスタンスである
正解と解説
正解:D. クラスはデータ(メンバ変数)と操作(メソッド)をまとめた型の定義であり、そこから実際に値をもつ実体として作られたものがインスタンスである

クラスは設計図にあたる型の定義で、それ自体は値を持たない。設計図から作られた、値をもつ実体がインスタンスであり、作る操作をインスタンス化という。選択肢1と2は設計図と実体の関係が逆になっている。1つのクラスからは値の異なるインスタンスをいくつでも作れるので選択肢3も誤りで、継承はインスタンスを増やすための仕組みではなく、既存クラスの性質を引き継いで別のクラスを定義する仕組みである。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類4:開発技術 中分類12:システム開発技術(オブジェクト指向設計)/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問16|空のとき

次のプログラムで、Stat のインスタンスを作った後、add を一度も呼び出さずに average() を呼び出したときの動作の説明として、正しいものはどれか。

件数0という境界を守る分岐
クラス: Stat  整数型: sum  整数型: cnt  ○Stat()    sum ← 0    cnt ← 0  ○add(整数型: v)    sum ← sum + v    cnt ← cnt + 1  ○整数型: average()    if (cnt = 0)      return 0    endif    return sum ÷ cnt の商
  1. 11行目の条件が成り立つので0が返り、0による除算は起こらない
  2. 11行目の条件は成り立たず、14行目で cnt が0のまま除算が行われて正しく動かない
  3. average() は呼び出せず、4行目のコンストラクタで誤りになる
  4. sum も cnt も未定義の値のままなので、戻り値は未定義の値になる
正解と解説
正解:A. 11行目の条件が成り立つので0が返り、0による除算は起こらない

コンストラクタ(4行目から6行目)で sum と cnt はどちらも0に初期化されている。add を呼ばなければ cnt は0のままなので、11行目の cnt = 0 が成り立ち、12行目で0が返る。したがって14行目の除算には到達せず、0による除算は起こらない。この11行目から13行目の分岐こそが、要素が1つも無いという境界を守るための処理である。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類4:開発技術 中分類12:システム開発技術(オブジェクト指向設計)/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問17|何のクラス

次のクラス Buf が実現しているデータ構造はどれか。ここで、配列 a には十分な大きさがあるものとする。

配列と1つの位置で作られたデータ構造
クラス: Buf  整数型の配列: a  整数型: n  ○Buf(整数型の配列: init)    a ← init    n ← 0  ○put(整数型: v)    n ← n + 1    a[n] ← v  ○整数型: take()    整数型: v    v ← a[n]    n ← n - 1    return v  ○論理型: isEmpty()    return n = 0
  1. 先入先出(FIFO)のキュー
  2. 値の小さい順に取り出す優先度付きキュー
  3. 後入先出(LIFO)のスタック
  4. 要素をつねに昇順に保つ整列済みリスト
正解と解説
正解:C. 後入先出(LIFO)のスタック

put は n を1増やしてから a[n] に入れ、take は a[n] を取り出してから n を1減らす。どちらも同じ位置 n を出入口にしているので、最後に入れた値が最初に出てくる。put(1)、put(2)、put(3) の後に take を3回呼ぶと3、2、1の順に返るので後入先出のスタックである。先入先出なら1、2、3の順になり、優先度付きキューや整列済みリストなら値の大小で順序が決まるが、この実装は値を一切比較していない。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類4:開発技術 中分類12:システム開発技術(オブジェクト指向設計)/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問18|空欄補充

次の手続き search は、1行目と2行目の仕様どおりに動く。7行目の空欄に入れる記述はどれか。

線形探索(7行目が空欄)
/* 仕様: 配列 a の中に値 x があれば、その最初の添字を返す。*//*       x が無ければ 0 を返す。                            */○整数型: search(整数型の配列: a, 整数型: x)  整数型: i  for (i を 1 から aの要素数 まで 1 ずつ増やす)    if (a[i] = x)      [                ]    endif  endfor  return 0
  1. return i
  2. return a[i]
  3. return x
  4. i ← i + 1
正解と解説
正解:A. return i

仕様は「値そのもの」ではなく「最初の添字」を返すことなので、見つけた時点の i を返す return i が正しい。a ← {7, 4, 9}、x ← 4 で試すと、正しい答えは添字の2だが、return a[i] も return x も値の4を返してしまう。i ← i + 1 は繰返しの制御変数を書き換えるだけで手続きから戻らないので、必ず最後まで進んで0が返り、値が存在しても見つけられない。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類1:基礎理論 中分類2:アルゴリズムとプログラミング(アルゴリズムの設計・計算量)/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問19|二分探索

次の手続き bsearch に、要素数が0の配列 a を渡したときの動作の説明として、正しいものはどれか。

二分探索(要素数0のときの動き)
○整数型: bsearch(整数型の配列: a, 整数型: x)  整数型: lo ← 1  整数型: hi ← aの要素数  整数型: mid  while (lo ≦ hi)    mid ← (lo + hi) ÷ 2 の商    if (a[mid] = x)      return mid    elseif (a[mid] < x)      lo ← mid + 1    else      hi ← mid - 1    endif  endwhile  return 0
  1. 3行目で hi が0になるため、6行目で a[0] を参照して誤りになる
  2. 5行目の条件がつねに成り立ち、無限ループになる
  3. 7行目の比較が1回だけ行われ、-1 が返る
  4. 5行目の条件 lo ≦ hi が最初から成り立たず、比較を一度も行わずに0が返る
正解と解説
正解:D. 5行目の条件 lo ≦ hi が最初から成り立たず、比較を一度も行わずに0が返る

要素数が0なら2行目で lo ← 1、3行目で hi ← 0 となる。5行目の lo ≦ hi は 1 ≦ 0 で成り立たないので、繰返しの中には一度も入らず、6行目の mid の計算も7行目の比較も実行されない。a[0] の参照は起きず、無限ループにもならない。そのまま15行目に進み、見つからなかったことを表す0が返る。この手続きは -1 ではなく0を返す点にも注意する。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類1:基礎理論 中分類2:アルゴリズムとプログラミング(アルゴリズムの設計・計算量)/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問20|探索の回数

昇順に整列済みで要素数が1,000の配列に対して二分探索を行うとき、探索する値と配列の要素との比較は、最悪の場合で何回必要か。

  1. 9
  2. 10
  3. 500
  4. 1,000
正解と解説
正解:B. 10

二分探索は1回比較するごとに候補の範囲が半分以下になる。1,000から始めて500、250、125、62、31、15、7、3、1、0と減るので、最悪でも10回で候補が尽きる。2の9乗が512で1,000に届かず、2の10乗が1,024で1,000を超えることからも10回と分かる。9回では要素数511までしか調べ切れない。500は半分にしただけの数、1,000は線形探索の最悪回数である。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類1:基礎理論 中分類2:アルゴリズムとプログラミング(アルゴリズムの設計・計算量)/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問21|0除算のバグ

次の手続き average は、1行目から3行目の仕様の一部を満たしていない。その原因はどれか。

平均を求める手続き(仕様は1〜3行目)
/* 仕様: 整数型の配列 a の要素の平均を、小数点以下を *//*       切り捨てた整数で返す。ただし a の要素数が0の *//*       ときは 0 を返す。                            */○整数型: average(整数型の配列: a)  整数型: i  整数型: sum ← 0  for (i を 1 から aの要素数 まで 1 ずつ増やす)    sum ← sum + a[i]  endfor  return sum ÷ aの要素数 の商
  1. 6行目で sum の初期値を0にしていること
  2. 7行目の繰返しの終わりが aの要素数 になっていること
  3. 要素数が0のときに0を返す分岐が無く、10行目で0による除算が起こること
  4. 10行目で商ではなく余りを求めていること
正解と解説
正解:C. 要素数が0のときに0を返す分岐が無く、10行目で0による除算が起こること

仕様には「要素数が0のときは0を返す」と書かれているが、手続きにはその分岐が無い。要素数が0だと7行目の繰返しは0回で sum は0のままとなり、10行目で 0 ÷ 0 の商を求めることになって破綻する。7行目の手前に要素数を調べて0を返す分岐を入れれば直る。合計の初期値0は正しく、繰返しの終わりを要素数にするのも全要素を足すために正しい。10行目は仕様どおり商(切捨て)を求めている。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類1:基礎理論 中分類2:アルゴリズムとプログラミング(アルゴリズムの設計・計算量)/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問22|入替えのバグ

次のプログラムで、17行目の sort(a) を呼び出した後の配列 a の中身はどれか。ここで、配列は参照渡しとする。

作業用変数を使わない入替え
/* 仕様: 整数型の配列 a を昇順に並べ替える */○sort(整数型の配列: a)  整数型: i, j  整数型: n ← aの要素数  for (i を 1 から n - 1 まで 1 ずつ増やす)    for (j を 1 から n - i まで 1 ずつ増やす)      if (a[j] > a[j + 1])        a[j] ← a[j + 1]        a[j + 1] ← a[j]      endif    endfor  endfor ○main()  整数型の配列: a  a ← {3, 1, 2}  sort(a)  /* ここで a の中身を調べる */
  1. {1, 1, 2}
  2. {1, 2, 3}
  3. {3, 1, 2}
  4. {2, 1, 3}
正解と解説
正解:A. {1, 1, 2}

8行目と9行目は作業用変数を使っていないため、入替えになっていない。i = 1、j = 1 で a[1] = 3 > a[2] = 1 が成り立ち、8行目で a[1] に1が入って a は {1, 1, 2} になる。9行目の a[2] ← a[1] は書き換わった後の1を入れるので変化しない。以降は a[2] = 1 > a[3] = 2 も a[1] = 1 > a[2] = 1 も成り立たず、最終的に {1, 1, 2} のままになる。正しく整列するには tmp などの作業用変数が要る。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類1:基礎理論 中分類2:アルゴリズムとプログラミング(アルゴリズムの設計・計算量)/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問23|手続きの仕様

次の手続き f の説明として、最も適切なものはどれか。ここで、a の要素数は1以上とする。

連続した並びを1回の走査で調べる
○整数型: f(整数型の配列: a)  整数型: i  整数型: best ← a[1]  整数型: cur ← a[1]  for (i を 2 から aの要素数 まで 1 ずつ増やす)    if (cur + a[i] > a[i])      cur ← cur + a[i]    else      cur ← a[i]    endif    if (cur > best)      best ← cur    endif  endfor  return best
  1. 配列 a の全要素の合計を返す
  2. 配列 a の要素のうち、最大のものを返す
  3. 配列 a の要素のうち、正の値だけを合計した結果を返す
  4. 配列 a の中で連続して並ぶ1個以上の要素の和のうち、最大のものを返す
正解と解説
正解:D. 配列 a の中で連続して並ぶ1個以上の要素の和のうち、最大のものを返す

cur は「いま見ている要素で終わる連続した並びの和の最大」を保つ変数で、6行目でそれまでの和に加えるか、その要素から新たに始めるかを選んでいる。best はその最大値を記録する。a ← {3, -4, 5, -1, 6, -9, 2} では 5 + (-1) + 6 = 10 が最大で、戻り値も10になる。全要素の合計は2、最大の要素は6、正の値だけの合計は16であり、いずれも10と一致しない。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類1:基礎理論 中分類2:アルゴリズムとプログラミング(アルゴリズムの設計・計算量)/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問24|要素数1

次の手続き maxGap に、要素数が1の配列(例えば {5})を渡したときの動作として、正しいものはどれか。

隣り合う要素を比べる手続き
/* 仕様: 整数型の配列 a について、隣り合う2要素の差の *//*       絶対値のうち、最大のものを返す。             */○整数型: maxGap(整数型の配列: a)  整数型: i  整数型: d  整数型: mx ← 0  for (i を 1 から aの要素数 - 1 まで 1 ずつ増やす)    d ← a[i + 1] - a[i]    if (d < 0)      d ← -d    endif    if (d > mx)      mx ← d    endif  endfor  return mx
  1. 7行目の繰返しの終わりが0になるため一度も実行されず、0が返る
  2. 8行目で a[2] を参照するため、正しく動かない
  3. a[1] の値がそのまま返る
  4. mx が未定義の値のまま返る
正解と解説
正解:A. 7行目の繰返しの終わりが0になるため一度も実行されず、0が返る

要素数が1なので、7行目は「i を 1 から 0 まで 1 ずつ増やす」となり、始まりが終わりより大きいので繰返しは1回も実行されない。したがって8行目の a[i + 1]、すなわち a[2] の参照は起きない。mx は6行目で0に初期化されているので、そのまま0が返る。隣り合う2要素が存在しないので、差を求めようがないという境界である。要素数が0のときも同じく0が返る。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類1:基礎理論 中分類2:アルゴリズムとプログラミング(アルゴリズムの設計・計算量)/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

問25|比較の回数

次の手続き g に、要素数が100の配列 a を渡したとき、7行目の比較は何回実行されるか。

すべての組合せを1回ずつ調べる二重の繰返し
○整数型: g(整数型の配列: a)  整数型: i, j  整数型: cnt ← 0  整数型: n ← aの要素数  for (i を 1 から n - 1 まで 1 ずつ増やす)    for (j を i + 1 から n まで 1 ずつ増やす)      if (a[i] = a[j])        cnt ← cnt + 1      endif    endfor  endfor  return cnt
  1. 4,900
  2. 4,950
  3. 5,000
  4. 9,900
正解と解説
正解:B. 4,950

内側の繰返しは i = 1 のとき j が2から100までの99回、i = 2 のとき98回…と1ずつ減り、i = 99 のとき1回になる。合計は 1 + 2 + … + 99 = 99 × 100 ÷ 2 = 4,950 回である。9,900は 100 × 99 で、同じ組を2回ずつ数えた値、5,000は 100 の2乗の半分、4,900は 70 の2乗であり、いずれも一致しない。回数は n(n - 1) / 2 なので、計算量としては O(n^2) と表す。

根拠:IPA 基本情報技術者試験 シラバス Ver.9.2 大分類1:基礎理論 中分類2:アルゴリズムとプログラミング(アルゴリズムの設計・計算量)/IPA 基本情報技術者試験 試験要綱 Ver.5.6 出題範囲(科目B試験)アルゴリズムとプログラミング

演習:この章の問題を解く

ランダム出題の演習ツールです(JavaScript が有効な場合に動きます)。上の「確認問題」はそのままでもすべて読めます。

※ 解説は学習用の情報提供です。最新の出題範囲・制度は必ずIPAの公式発表をご確認ください。
※ 出題はIPA公開のシラバスVer.9.2(2026年1月8日適用)に沿った仮の宿 学習室のオリジナル問題です。擬似言語の記述形式もIPA公開の仕様に合わせています。試験制度・実施要項はIPAの公式発表をご確認ください(2027年度春ごろに新試験制度へ移行予定)。