令和6年度 基本情報技術者試験 科目B 問4の解説|2本の配列を併合する merge

基本情報技術者試験

令和6年度 科目B 公開問題 問4擬似言語・while・配列の併合最終更新 2026-09-05

令和6年度の科目B、その4問目です。小さい順に並んだ配列を2本受け取って、1本の小さい順の配列にまとめるプログラムが出てきます。ただし聞かれているのは、できあがる配列ではありません。ある1行が、何回実行されるかです。この記事では、3つの番号が動くようすを自分の手で追って、解答群を1度も見ないまま回数を言えるところまで進みます。

出題

まず原文のまま読んでみてください。記号の読み方は次の節にまとめてありますので、読めなくてもここでは問題ありません。

出典:令和6年度 基本情報技術者試験 科目B 公開問題 問4

次の記述中の   に入れる正しい答えを,解答群の中から選べ。ここで,配列の要素番号は1 から始まる。

関数merge は,昇順に整列された整数型の配列data1 及びdata2 を受け取り,これらを併合してできる昇順に整列された整数型の配列を返す。

関数 merge を merge({2, 3}, {1, 4}) として呼び出すと,/*** α ***/ の行は   。

〔プログラム〕

○整数型の配列: merge(整数型の配列: data1, 整数型の配列: data2)
  整数型: n1 ← data1の要素数
  整数型: n2 ← data2の要素数
  整数型の配列: work ← {(n1 + n2)個の 未定義の値}
  整数型: i ← 1
  整数型: j ← 1
  整数型: k ← 1

  while ((i ≦ n1) and (j ≦ n2))
    if (data1[i] ≦ data2[j])
      work[k] ← data1[i]
      i ← i + 1
    else
      work[k] ← data2[j]
      j ← j + 1
    endif
    k ← k + 1
  endwhile

  while (i ≦ n1)
    work[k] ← data1[i]
    i ← i + 1
    k ← k + 1
  endwhile

  while (j ≦ n2)
    work[k] ← data2[j]  /*** α ***/
    j ← j + 1
    k ← k + 1
  endwhile

  return work

解答群

ア 実行されない

イ 1 回実行される

ウ 2 回実行される

エ 3 回実行される

答えだけ先に見る

正解は イ(1 回実行される)です。なぜ1回なのかは、この記事で最後まで自分の手でたどります。

この問題に出てくる記号

読めない記号があったときだけ開いてください。いま読めればいいのは12個だけで、細かいところは使う場面で足していきます。

擬似言語の記号 12コ の読み方をひらく
書き方 読み方
○整数型の配列: merge(…) ここから関数が1つ始まるという印。○ のうしろの 整数型の配列 は返すものの型、括弧の中が受け取るものです。ここでは配列を2本受け取って、配列を1本返します
整数型: i ← 1 i という箱を1つ用意して、1 を入れる。整数型 なので整数だけが入ります
a ← b 右の値を、左へ入れる。入れられた側(左)は前の中身が消えて上書きされます。読まれた側(右)はそのままです
data1[i] 配列 data1 の i 番目の枡。角かっこの中を添字といい(出題文の要素番号と同じものです)、箱の名前(変数)も書けます(i が 2 なら data1[2])。この試験では 1 から数えます
data1の要素数 その配列に入っている枡の個数。{2, 3} なら 2 です
{(n1 + n2)個の 未定義の値} 枡だけ用意して、中身は空という配列。n1 と n2 がどちらも 2 なら、4枡ぶん用意されます。この「中身が空」の状態を未定義といいます
while (…)
endwhile
かっこの中が成り立つあいだ、endwhile までをくり返す。くり返しに入る前に、毎回かならず条件を見ます ── だからはじめから成り立たなければ、中は1回も実行されません。くり返しの1回ぶんを、この記事では「1周」と呼びます
if (…)
else
endif
かっこの中が成り立つときだけ else までの行を、成り立たなければ else から endif までの行を実行する
a ≦ b 左が右以下のとき成り立つ。等しいときも成り立ちます
and 左右がどちらも成り立つときだけ成り立つ。片方でも成り立たなければ、全体が成り立ちません
return ◯ ◯ を返して、その関数はそこで終わり。呼んだ側にその値が渡ります
/*** α ***/ 注釈。人が読むための書き込みで、それ自体は何も実行しません。この問題では行に名札を貼るために使われていて、聞かれているのはその名札が貼られた行のほうです

記号でつまずいたら、下の教科書から、先にそこだけ読んでください(G7 のような番号は、当サイトの擬似言語の教科書の第何回かを表します)。

3本の配列と、3つの番号

併合とは、小さい順に並んだ列を2本受け取って、小さい順に並んだ1本の列にまとめることです(出題文の「昇順に整列された」が、この「小さい順に並んだ」にあたります)。この問題では data1 と data2 を受け取り、work という3本目の配列に答えを書いていきます。

プログラムはまず、data1 の枡の数を n1、data2 の枡の数を n2 に入れます ── どちらもここでは 2 です。そして、いま見ている場所をおぼえておく箱を3つ用意します。

3つの番号が、それぞれ別の配列を見ている

i data1 の次に見る枡の番号

j data2 の次に見る枡の番号

k work の次に書く枡の番号

3つとも整数を入れる箱で、中身が枡の番号です。この記事ではまとめて「番号」と呼びます。

出発の形 ── 3本の配列と、3つの番号がどこを指しているか

▲=その番号がいま指している枡 / 網掛け=未定義(まだ何も入っていない)

merge({2, 3}, {1, 4}) が呼ばれた直後

n12

n22

i1

j1

k1

data1

12▲

23

work

1未定義▲

2未定義

3未定義

4未定義

data2

11▲

24

data1 も data2 も小さい順に並んでいます。work は n1 + n2 = 4 枡で、中身は4つとも未定義。3つの番号は、どれも 1 から始まります。

work を真ん中に置いてあります。上の data1 と下の data2 から、真ん中へ集めていきます。

1周ですることは2つだけです。① data1[i] と data2[j] をくらべて、小さいほうを work[k] へ写す(判定は data1[i] ≦ data2[j] なので、同じ値のときは data1 側が写ります)。② 写したほうの番号だけを1つ進める(k は毎周かならず進みます)。写さなかったほうの番号は、そのまま次の周にも残ります。

手で動かす ── 1つ目の while を最後まで

呼び出しは merge({2, 3}, {1, 4})。data1 が {2, 3}、data2 が {1, 4} です。動かすのは、この10行だけです。

〔プログラム〕1つ目の while(この節で動かすのはここだけ)

  while ((i ≦ n1) and (j ≦ n2))
    if (data1[i] ≦ data2[j])
      work[k] ← data1[i]
      i ← i + 1
    else
      work[k] ← data2[j]
      j ← j + 1
    endif
    k ← k + 1
  endwhile

※ 上の〔プログラム〕からの抜粋です(1字も変えていません)。

止まるところまで、1周ずつ進めます。

1つ目の while ── くらべて、小さいほうを真ん中へ写す

▲= i・j・k がいま指している枡(data1 と data2 の ▲ が、その周にくらべる2枡) / 琥珀=その周に写した値(写しもと) / 緑=その周に書き込まれた枡 / 灰=もう写し終えた枡 / 網掛け=未定義。「次へ」で1周ずつ進みます。

① 1周目 ── data1[1] の 2 と data2[1] の 1 をくらべる

i1

j1

k1

data1

12▲

23

work

11▲

2未定義

3未定義

4未定義

小さいほうの 1 を写す

data2

11▲

24

条件は (1 ≦ 2) and (1 ≦ 2) で成り立ちます。2 ≦ 1 は成り立たないので else のほうへ進み、data2 側の 1 を写します。進むのは j だけで、i は 1 のままです。

② 2周目 ── data1[1] の 2 と data2[2] の 4 をくらべる

i1

j2

k2

data1

12▲

23

小さいほうの 2 を写す

work

11

22▲

3未定義

4未定義

data2

11

24▲

条件は (1 ≦ 2) and (2 ≦ 2) で成り立ちます。2 ≦ 4 が成り立つので data1 側の 2 を写します。今度は i だけが進みます。

③ 3周目 ── data1[2] の 3 と data2[2] の 4 をくらべる

i2

j2

k3

data1

12

23▲

小さいほうの 3 を写す

work

11

22

33▲

4未定義

data2

11

24▲

条件は (2 ≦ 2) and (2 ≦ 2) で成り立ちます。3 ≦ 4 が成り立つので data1 側の 3 を写し、i が 3 に。これで data1 は2枡とも写し終えました。

④ 4周目に入ろうとして、止まる

i3

j2

k4

data1

12

23

work

11

22

33

4未定義▲

data2

11

24▲

条件をもう一度見ます。i ≦ n1 は 3 ≦ 2 で成り立ちません。and は片方でも成り立たなければ全体が成り立たないので、ここで1つ目の while を抜けます。i は 3 ── data1 の枡の外を指しているので、▲ が付きません。そして data2 の 4 は、まだ写されていません。

3周で work は {1, 2, 3, 未定義}。抜けた時点で i = 3、j = 2。

4周目に入ろうとしたところで、i が data1 の枡の数を超えていたので止まりました。この while は、data1 と data2 のどちらか一方が尽きた瞬間に止まります。

コードの中で、3つの while は何をする行か

いま手で動かしたことを、プログラムの各行に当てはめます。while が3つ並んでいるのが、このプログラムの形です。

○整数型の配列: merge(整数型の配列: data1, 整数型の配列: data2)

受け取るのは配列2本、返すのも配列

整数型: n1 ← data1の要素数

data1 の枡の数。ここでは 2

整数型: n2 ← data2の要素数

data2 の枡の数。ここでは 2

整数型の配列: work ← {(n1 + n2)個の 未定義の値}

答えを書く先。2 + 2 = 4 枡を、すべて未定義で用意する

整数型: i ← 1

data1 の次に見る枡の番号

整数型: j ← 1

data2 の次に見る枡の番号

整数型: k ← 1

work の次に書く枡の番号

 

 

while ((i ≦ n1) and (j ≦ n2))

1つ目。両方に残りがあるあいだ。and なので片方が尽きたら止まる

if (data1[i] ≦ data2[j])

先頭どうしをくらべる

work[k] ← data1[i]

data1 側を写す

i ← i + 1

写した側の番号だけ進む

else

 

work[k] ← data2[j]

data2 側を写す

j ← j + 1

写した側の番号だけ進む

endif

 

k ← k + 1

書く先は毎周かならず1つ進む

endwhile

 

 

 

while (i ≦ n1)

2つ目。data1 に残っていた分を、そのまま後ろへ写す

work[k] ← data1[i]

 

i ← i + 1

 

k ← k + 1

 

endwhile

 

 

 

while (j ≦ n2)

3つ目。data2 に残っていた分を、そのまま後ろへ写す

work[k] ← data2[j] /*** α ***/

この行が問われている行。うしろの注釈は名札で、実行されない

j ← j + 1

 

k ← k + 1

 

endwhile

 

 

 

return work

並べ終わった配列を返す

※ 右側の注釈は当サイトで書き加えたものです。プログラム自体は原文のまま引用しています。

3つの while の役割

1つ目 両方に残りがあるあいだ、小さいほうを写す

2つ目 data1 に残っていた分を写す

3つ目 data2 に残っていた分を写す ── 問われている行はここ

問われている行が何回実行されるかを決める

決めるのは、後ろの2つの while です。

〔プログラム〕2つ目の while(data1 の残りを写す)

  while (i ≦ n1)
    work[k] ← data1[i]
    i ← i + 1
    k ← k + 1
  endwhile

※ 上の〔プログラム〕からの抜粋です(1字も変えていません)。

〔プログラム〕3つ目の while(問われている行を含む)

  while (j ≦ n2)
    work[k] ← data2[j]  /*** α ***/
    j ← j + 1
    k ← k + 1
  endwhile

※ 上の〔プログラム〕からの抜粋です(1字も変えていません)。

どちらも、条件は1つ目の while を抜けた時点の i と j で決まります。そこがどうなっていたかを、もう一度見ます。

1つ目の while を抜けたところ ── 残っているのはどちらの配列か

灰=もう写し終えた枡 / 琥珀の破線=まだ写していない、残っている枡 / ▲= j・k がいま指している枡 / 網掛け=未定義

n12

n22

i3

j2

k4

data1

12

23

work

11

22

33

4未定義▲

data2

11

24▲

data1 は 2 も 3 も写し終えて、i は 3 ── 枡の外です。写していないのは data2 の 4 だけ。

data1 の残り 0個 / data2 の残り 1個。

2つ目の while の条件は i ≦ n1。i は 3、n1 は 2 なので 3 ≦ 2 は成り立ちません。while はくり返しに入る前に条件を見るので、この while の中は 1回も実行されません。

3つ目の while の条件は j ≦ n2。j は 2、n2 は 2 なので 2 ≦ 2 は成り立ちます。中に入り、問われている行が実行されて、残っていた 4 が work[4] へ入ります。そのあと j が 3 になり、もう一度条件を見ると 3 ≦ 2 は成り立たないので、そこで終わりです。

この while は、j を1つずつ進めながら n2 を超えるまで回ります。つまり回る回数は、入ってきた時点で data2 に残っていた個数そのものです。ここでは残りが 1個だったので、1回。

問われている行が実行される回数

1 回。3つ目の while が回る回数は、1つ目の while が data2 に残した個数と同じです。

ここで初めて解答群を見る

1回。解答群でこの回数は イ ひとつだけです。

答え合わせ ── 入れて動かすと、問われている行を1回だけ通る

はじめから最後まで、1行ずつ通します。見るのは i・j・k の3つの番号と、work です。

1行ずつ追う merge({2, 3}, {1, 4})

出典:令和6年度 科目B 公開問題 問4


ループ開始前

3本の配列

▲ いま読んでいる▲ いま書いた

いま計算していること

まだ計算していません

変数の状態

トレース表(進めると1行ずつ積み上がります)

正解は イ

問われている行を通るのは 1回だけ。返る配列は {1, 2, 3, 4} です。

ほかの3つは、data2 の残りが違う呼び出しでの回数です。同じプログラムでも、渡す配列が変われば回数はこう変わります。

ア(0回) data2 の残りが 0個。先に尽きるのが data2 のほうだった場合です。merge({1, 4}, {2, 3}) なら、j が 3 になって1つ目の while が止まり、残った 4 は2つ目の while が写します。

イ(1回) data2 の残りが 1個。本問の merge({2, 3}, {1, 4}) がこれです。

ウ(2回) data2 の残りが 2個。merge({1}, {2, 3}) なら、1つ目の while は1周で data1 を使い切り、data2 の 2 と 3 が丸ごと残ります。

エ(3回) data2 の残りが 3個。同じように、data1 が先に尽きて data2 が3つ余った場合です。

次に読む

この問題でどこに手間取ったかで、行き先が変わります。

この記事で引用した資料

いずれも独立行政法人情報処理推進機構(IPA)が公表したものです。IPAは公表済みの試験問題について、教育目的での使用に許諾および使用料を不要としていますが、著作権は放棄していません。本記事では問題文を改変せずに引用しています。

「別の呼び出しで確かめる例(merge({1, 4}, {2, 3}))」は当サイトのオリジナルです。

Copied title and URL