分割して並べる|マージソートとクイックソート【基本情報技術者試験 科目B】

現行FE シラバス Ver9.2 準拠擬似言語の記述形式は2022年から変更なし最終更新 2026-08-23

整列の3本目です。バブル・選択や挿入は、並び全体を1本のくり返しで片づけるやり方でした。ここからは割って、それぞれを片づけるやり方に変わります。

第2部 定番処理の型 全26回

A1-1トレース表の書き方A1-2繰返しのトレースA1-3配列のトレースA2-1配列を全部見るA2-2最大・最小を見つけるA2-3探す(線形探索)A2-4入れる・消すA3-12次元配列の走査A3-22次元配列の集計A4-1文字列を1文字ずつA4-2文字列照合A5-1交換して並べるA5-2挿入ソートA6分割して並べるA7-12分探索A7-2ハッシュ表探索A8-1再帰とはA8-2再帰のトレースA9スタックとキューA10-1リストを読むA10-2リストの挿入と削除A11木構造A12木の巡回A13グラフA14AI・データを題材にしたプログラムA15ファイル処理

大きいまま解かず、割ってから解く

4つをいっぺんに並べるのは面倒です。でも半分に割れば2つずつ。もう一度割れば1つずつになります。そして1つなら、もう並んでいます。

4つを2つずつ、さらに1つずつに割っていく分割統治の図

1つになるまで割れば、並べる作業は消える

分割統治

大きい問題を小さい問題に割って、同じやり方でまた解く。これを分割統治といいます。シラバスにも用語として載っています。

割っただけでは、並びません

割るのはただ半分にするだけで、何も考えていません。並べる仕事は消えたのではなく、戻すときに回されています。次に見るのは、その戻し方です。

「同じやり方でまた解く」ので、手続が自分自身を呼びます。これが再帰です。ここでは「自分を呼ぶ行がある」とだけ分かれば足ります。

マージソート【手順1】1つになるまで、半分に割る

まずひたすら半分に割ります。中身は見ません。ただ真ん中で切るだけです。

4つを2つずつ、さらに1つずつに割っていく分割統治の図

1つになるまで割れば、並べる作業は消える

{5, 3, 8, 1} なら、{5, 3} と {8, 1}。もう一度割って {5} {3} {8} {1}。1つになったら、それはもう並んでいます。ここまでは何も並べ替えていません。

マージソート【手順2】並べながら、戻していく

ここからが本番です。2本ずつ、並べながらくっつけて戻します。

1つずつに割ったものを2つずつ併合し、最後に1本に戻す

割るのは簡単。むずかしいのは戻すとき

やり方は1つだけ。2本の先頭どうしを比べて、小さいほうを取る。取ったほうだけ1つ進める。これをくり返します。

最後の併合を、手で追う

{3, 5} と {1, 8}先頭は 3 と 1。小さい 1 を取る

{3, 5} と {8}先頭は 3 と 8。小さい 3 を取る

{5} と {8}先頭は 5 と 8。小さい 5 を取る

{} と {8}片方が空。残った 8 はそのまま写す

{1, 3, 5, 8} のできあがりです。比べた回数は4回だけ。両方すでに並んでいるので、先頭以外を見る必要がありません。

併合を、プログラムで書く

いま手で追った最後の併合を、そのままプログラムにします。a と b が併合する2本、out が結果です。

整数型の配列: a ← {3, 5}
整数型の配列: b ← {1, 8}
整数型の配列: out ← {}
整数型: p ← 1
整数型: q ← 1

while (p ≦ aの要素数 and q ≦ bの要素数)
  if (a[p] ≦ b[q])
    outの末尾 に a[p]の値 を追加する
    p ← p + 1
  else
    outの末尾 に b[q]の値 を追加する
    q ← q + 1
  endif
endwhile
while (p ≦ aの要素数)
  outの末尾 に a[p]の値 を追加する
  p ← p + 1
endwhile
while (q ≦ bの要素数)
  outの末尾 に b[q]の値 を追加する
  q ← q + 1
endwhile

当サイトで作った例です。

実行すると out は {1, 3, 5, 8} になります。p と q がそれぞれの「いま見ている位置」です。while が3つあるのは、片方が尽きたら比べる相手がいなくなるから。2つ目と3つ目が、残ったほうをそのまま写すところです。

併合を1行ずつ動かす

当サイトオリジナルの例題


ループ開始前

並んでいる2本と、併合先

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

いま計算していること

まだ計算していません

変数の状態

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

p と q が別々に動くところは、止まった絵では追えません。動画で1周ずつ見てください。

並んだ2本を、1本にまとめる(2分17秒・音声つき)

再生できないときは、この下の図と説明で同じ内容を追えます。

番号(添字)が2つ要るのは、どういうときか

2本の要素数が同じで、同じ番号が同じものを指すなら、番号は1つで足ります(A2-1)。

ここのように 2本を先頭から見比べて、取り出した側だけを進めるなら、2つ要ります。毎周どちらか片方しか進みません。

マージソートの重さは、戻すところにある

割るのはただ半分にするだけで、何も考えません。仕事はすべて併合のときに起きます。

クイックソート ── 基準値で振り分ける

こちらは順序が逆です。割る前に振り分けます。

基準値 3 で小さいものを左、大きいものを右へ振り分け、左右をそれぞれ並べる

割る前に振り分ける。だから戻すときは何もしない

やること

①基準値(pivot)を1つ決める

②それより小さいものを左、大きいものを右へ寄せる

③左と右を、それぞれ同じやり方で並べる

②が終わった時点で、基準値の位置は決まっています。左には小さいものしかなく、右には大きいものしかないからです。だから戻すときに併合は要りません。

実際の出題にそのまま出ている

令和5年度の科目Bに、大域の配列 data の、first 番目から last 番目までを昇順に整列する sort という手続が出ています。

基準値の決め方は pivot ← data[(first + last) ÷ 2 の商]。まん中の要素を選んでいます。÷ 2 の商 は、2で割った整数の商という意味です(A2-1)。

最後に sort(first, i - 1) と sort(j + 1, last) ── 自分を2回呼んでいます。左半分と右半分です。

2つのちがい

マージソート クイックソート
割り方 まん中で機械的に半分 基準値で振り分けてから割る
仕事の場所 戻すとき(併合) 割る前(振り分け)
戻すとき 2本を突き合わせて併合 何もしない。すでに並んでいる
別の場所 併合先の配列が要る 元の配列の中だけで済む

試験では「途中経過を答えよ」という形で問われます。どちらなのかは、割ったあとに併合の行があるかどうかで見分けられます。

つまずきポイントまとめ

まちがえ方 正しい読み方
クイックソートでも併合すると思う 振り分け済みなので併合は要らない
マージソートで割るときに何か考える 割るのは機械的に半分。仕事は戻すとき
÷ 2 を切り捨てだと思う 切り捨ては の商 が付いたとき
自分を呼ぶ行を見落とす 手続の中に、同じ名前の呼び出しがある
基準値が最後に動くと思う 振り分けた時点で位置は確定

次に読む

第2部 科目Bのアルゴリズム ─ 出るものの地図
A5-2 挿入ソート ─ 手札を並べるのと同じ
目次 基本情報技術者試験 科目B 攻略ガイド

この記事で引用した資料

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

本文の例題は当サイトのオリジナルです。

Copied title and URL