クイックソートのアルゴリズム|新しい擬似言語で学ぶ 科目 B アルゴリズムとプログラミング入門


2023-07-19 更新

基本情報技術者試験は、 2023 年 4 月から新制度で実施されています。

この連載では、新制度で採用された新しい擬似言語(旧制度の擬似言語とは、表記方法に違いがあります)を使って、試験のシラバス(情報処理技術者試験における知識・技能の細目)に示されている代表的なアルゴリズムとデータ構造を、プログラミング入門者向けにやさしく解説します。 受験対策としてだけでなく、アルゴリズムとプログラミングの基礎知識を習得するために、ぜひお読みください。

前回は 再帰呼び出し を取り上げました。 今回は、再帰呼び出しを使った クイックソート を取り上げます。

クイックソートのアルゴリズム

クイックソートは、配列をソートするアルゴリズムの一種です。 クイックソートのアルゴリズムは以下です。

format_quote

配列の中から基準値を選び、残りの要素を基準値より小さいグループと大きいグループに分けることを、グループの要素数が 1 個になるまで( 2 個以上である限り)繰り返す

format_quote

グループ分けすることでソートの対象となる配列の要素数が徐々に少なくなることと、プログラムで繰り返しを実現するときに再帰呼び出し(関数や手続の処理の中で、同じ関数や手続を呼び出すことで、繰り返しを実現するプログラミング技法)を使うことが、クイックソートの特徴です。

 

図 1 は、要素数 7 個の配列(要素番号は 1 から始まるとします)を昇順にクイックソートする手順の例を示したものです。

図 1 要素数 7 個の配列を昇順にクイックソートする手順の例

ここでは、ソート対象となる配列の真ん中の要素を基準値としています。

真ん中の要素の要素番号は、

(左端の要素の要素番号 + 右端の要素の要素番号) ÷ 2

という計算で求められます。 要素番号は、整数型のデータなので、除算結果の小数点以下はカットされます。

初期状態(図 1 の【手順 1 】)では、ソート対象となる配列が a[1] ~ a[7] なので、

(1 + 7) ÷ 2 = 4

となり、 a[4] に格納されている 4 が基準値です。

図 1 要素数 7 個の配列を昇順にクイックソートする手順の例


配列の先頭から基準値より大きい値を探索し、配列の末尾から基準値より小さい値を探索して、大きい値と小さい値を交換することを繰り返すと、基準値との大小関係で配列のグループ分けができます。

図 1 要素数 7 個の配列を昇順にクイックソートする手順の例


同じ手順を、グループ分けしたそれぞれのグループで繰り返します。 グループの要素数が 1 個になったら繰り返しを終了します。 すべてのグループの繰り返しが終了したら、配列全体のソートが完了します。

クイックソートのプログラム

リスト 1 は、クイックソートのプログラムの例です。

これは、 2023 年 7 月 6 日に情報処理推進機構から公開された「令和 5 年度 基本情報技術者試験 科目 B 公開問題」の問 3 に示されたプログラムに、若干のアレンジを加えたものです。

手続 sort は、配列を昇順にクイックソートします。
引数 a は、ソート対象の配列です。
引数 first は、ソート対象の先頭の要素番号です。
引数 last は、ソート対象の末尾の要素番号です。
配列の要素番号は、 1 から始まるとします。

swipeプログラムは横スクロールできます

リスト 1code クイックソートのプログラムの例
sort(整数型の配列: a, 整数型: first, 整数型: last)
  整数型 pivot, i, j, temp

  /* 配列の真ん中の要素を基準値とし
     基準値の要素番号を pivot に設定する */
  pivota[(first + last) ÷ 2]

  /* 配列の先頭の要素番号を i に設定する */
  ifirst

  /* 配列の末尾の要素番号を j に設定する */
  jlast

  /* 無限ループで繰り返す */
  while (true)
    /* 配列の先頭から pivot 以上の要素を探索し、見つかった位置を i に得る */
    while (a[i] < pivot)
      ii + 1
    endwhile

    /* 配列の末尾から pivot 以下の要素を探索し、見つかった位置を j に得る */
    while (pivot < a[j])
      jj - 1
    endwhile

    /* 探索の範囲を超えているなら */
    if (ij)
      /* グループ分けが完了しているので無限ループを抜ける
         breakは、繰り返しを抜けるメールだとする */
      break
    endif

    /* 基準値の前側にある基準値以上の a[i] と
       基準値の後側にある基準値以下の a[j] を交換する*/
    temp ← a[i]
    a[i]a[j]
    a[j]temp
  endwhile

  /* グループ分けした前側の要素数が 2 個以上なら */
  if (first < i - 1)
    /* 再帰呼び出しで、前側で同じ処理を繰り返す */
    sort(a, first, i - 1)
  endif

  /* グループ分けした後側の要素数が 2 個以上なら */
  if (j + 1 < last)
    /* 再帰呼び出しで、後側で同じ処理を繰り返す */
    sort(a, j + 1, last)
  endif

プログラムに多くのコメントを入れてあります。 コメントを参考にして、プログラムの処理内容を読み取ってください。

注目してほしいのは、再帰呼び出しで繰り返しを行っている部分です。 手続 sort は、

「基準値を決め、ソート対象の配列を基準値との大小関係でグループ分けする」

という処理を行います。

この処理を、グループ分けされた前側と後側で繰り返すので、 sort( ソート対象の配列 ) の処理の中で、 sort( 前側のグループ )sort( 後側のグループ ) を呼び出すのです。 この部分が、再帰呼び出しです。

グループの要素数が 1 個になるまで( 2 個以上である限り)、この再帰呼び出しを繰り返します。

基本情報技術者試験の公開問題にチャレンジ

最後に、試験対策として「令和 5 年度 基本情報技術者試験 科目 B 公開問題」の問 3 にチャレンジしてみましょう。

基本情報技術者試験の科目 B 試験では、 100 分で 20 問を解きます。 1 問当たりの解答時間の目安は、

100 分 ÷ 20 問 = 5 分

です。

この問題の中には「クイックソート」という言葉はありませんが、クイックソートのプログラムを学んだ経験があれば「あっ! これはクイックソートだ」とすぐにわかり、 5 分程度ですんなり問題を解けるでしょう。 逆に、クイックソートのプログラムを学習した経験がないと、相当な時間がかかるか、まったくお手上げでしょう

この問題から、試験対策として、シラバスに示されたアルゴリズムとデータ構造をきちんと学ぶことの重要性を感じてください。 「きちんと学ぶ」とは、単にアルゴリズムを理解するだけでなく、実際のプログラムでどのような処理になるのかを経験することです。

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

 次の手続 sort は,大域の整数型の配列 data の,引数 first で与えられた要素番号から引数 last で与えられた要素番号までの要素を昇順に整列する。ここで, first
< last とする。 手続 sort を sort(1, 5) として呼び出すと, /*** α ***/ の行を最初に実行したときの出力は “” となる。

プログラムcode

大域: 整数型の配列: data ← {2, 1, 3, 5, 4}

○sort(整数型: first, 整数型: last)
 整数型: pivot, i, j
 pivot ← data[(first + last) ÷ 2 の商]
 i ← first
 j ← last

 while (true)
  while (data[i] < pivot)
    i ← i + 1
  endwhile
  while (pivot < data[j])
    j ← j - 1
  endwhile
  if (i ≧ j)
    繰返し処理を終了する
  endif
  data[i] と data[j] の値を入れ替える
  i ← i + 1
  j ← j - 1
 endwhile
 data の全要素の値を要素番号の順に空白区切りで出力する /*** α ***/
 if (first < i - 1)
   sort(first, i - 1)
 endif
 if (j + 1 < last)
   sort(j + 1, last)
 endif

解答群
ア 1 2 3 4 5
イ 1 2 3 5 4
ウ 2 1 3 4 5
エ 2 1 3 5 4

先ほどリスト 1 に示したプログラムでは、ソート対象の配列を手続 sort の引数で指定していましたが、公開問題のプログラムでは、大域の配列(プログラムのどこからでも使える配列)としています。 これは、プログラムの内容をシンプルにするためでしょう。

このプログラムの処理内容は、リスト 1 に示したプログラムと同様です。 ここでは、

data ← {2, 1, 3, 5, 4}

という配列を最初にグループ分けした後で、 data の全要素の値を要素番号の順に空白区切りで出力した結果を、解答群の中から選びます。

最初のグループ分けでは、

{2, 1, 3, 5, 4}

の 3 を基準値として、配列全体をグループ分けします。

{2, 1, 3, 5, 4}

は、 3 の前に 3 より小さい値があり、 3 の後に 3 より大きい値があるので、要素の値の交換は行われず、このままでグループ分けが完了しています。

したがって、

2 1 3 5 4

と表示されます。 選択肢エが正解です。

今回は、クイックソート取り上げました。

次回以降も、シラバスに示されたアルゴリズムとデータ構造を学んでいきます。

それでは、またお会いしましょう!

info_outline関連記事

新制度・基本情報技術者試験の過去問(公開問題)からわかる難易度と対策

label 関連タグ
科目A試験は、
免除できます。
独習ゼミで科目A試験を1年間免除して、科目B試験だけに集中しましょう。
免除試験を受けた 74.9% の方が、
科目A免除資格を得ています。
科目A免除試験 最大 2 回の
受験チャンス !
info_outline
科目A免除試験 最大 2 回の
受験チャンス !
詳しく見てみるplay_circle_filled
label これまでの『新しい擬似言語で学ぶ 科目 B アルゴリズムとプログラミング入門』の連載一覧

マージソート|新しい擬似言語で学ぶ 科目 B アルゴリズムとプログラミング入門

update

二分木の深さ優先探索と幅優先探索|新しい擬似言語で学ぶ 科目 B アルゴリズムとプログラミング入門

update

比べてわかるキューとスタックの仕組み|新しい擬似言語で学ぶ 科目 B アルゴリズムとプログラミング入門

update

「リスト」というデータ構造|新しい擬似言語で学ぶ 科目 B アルゴリズムとプログラミング入門

update

サーチのアルゴリズム (3) ハッシュ表探索法のアルゴリズム|新しい擬似言語で学ぶ 科目 B アルゴリズムとプログラミング入門

update

クイックソートのアルゴリズム|新しい擬似言語で学ぶ 科目 B アルゴリズムとプログラミング入門

update

再帰呼び出しのアルゴリズム|新しい擬似言語で学ぶ 科目 B アルゴリズムとプログラミング入門

update

サーチのアルゴリズム (2) 二分探索法|新しい擬似言語で学ぶ 科目 B アルゴリズムとプログラミング入門

update

サーチのアルゴリズム (1) 線形探索法|新しい擬似言語で学ぶ 科目 B アルゴリズムとプログラミング入門

update

多重ループを使うバブルソート|新しい擬似言語で学ぶ 科目 B アルゴリズムとプログラミング入門

update
label 著者