C言語入門(選択ソート)

C言語

お疲れ様です。サンチョです!
今回は「選択ソート」について触れてみます。

今回の記事を読んで得られるものは以下の通りです。
(1)選択ソートのイメージ
(2)プログラムに落とし込む際の思考の流れ

選択ソートとは

配列の中から要素を1つ選択して、それをほかの要素の値と比較し、最小値、または最大値を見つけだして入れ替えていくソート処理のことです。

選択ソートのイメージ

ソート前の情報が [ 4 ][ 1 ][ 3 ][ 5 ][ 2 ] だったしてイメージを説明します。
今回はこれを降順(大きい順)で並べ替える例を紹介します。

1つ目の要素を最大値と仮定する

まず最大値の格納場所となる変数を用意して、1つ目の要素を退避します。
1つ目の要素を最大値と仮定するということです。

最大値と2つ目以降の要素を順番に比較して最大値をみつける

続いて、最大値と残りの要素( [ 1 ][ 3 ][ 5 ][ 2 ] )を順番に比較していきます。

すると [ 4 ] より大きな値である [ 5 ] が見つかるで、最大値を [ 5 ] に変更します。
そのあとも引き続き、最大値と残りの要素を比較していきます。
もし残りの要素の中に [ 5 ] より大きな値が見つかれば、再び最大値を変更します。
これを繰り返すと最大値が判明します。

1つ目の要素と最大値の要素を入れ替える

次に1つ目の要素と最大値を入れ替えます。

これによって1つ目の要素を最大値とすることができました。

次は2つ目の要素を2つ目の最大値と仮定して、同様の処理を繰り返していけば、最終的に降順に並び替えることができます。

実際にやってみよう

まずは考えを整理する

まずはイメージを元にどういう処理が必要か整理しましょう。

(1)配列の要素を1つずつ取り出さないといけないので、ループ処理が必要。
(2)選択された最大値を、配列の各要素と比較するには、もうひとつループ処理が必要。
(3)比較するということは、条件分岐(if文)が必要。
(4)配列のデータを入れ替える処理が必要。

続いて、上記の処理を実行するために必要な変数を整理しましょう。

(1)int型の配列変数が必要。
(2)2つのループを回すために、2つのカウンタ変数が必要。
(3)最大値の要素番号を退避するための int型の変数が必要。
(4)データの入れ替えを行うために、値を退避するための int型の変数が必要。

整理した流れを元にプログラミングする

整理した流れを元に完成したのが以下のプログラムです。
ソート前とソート後の結果を比較しやすいように、オマケで表示用の関数も作ってみました。

#include<stdio.h>
void printArray(int data[]);

int main() {
    int data[5] = { 4, 1, 3, 5, 2 }; // 配列
    int outCnt, // 外側のループを回すためのカウンタ変数
        inCnt;  // 内側のループを回すためのカウンタ変数
    int temp;   // 配列の値を交換するための退避用変数
    int max;    // 最大値が格納されている要素番号を記憶するための変数

    printf("ソート前\n");
    printArray(data);

    for (outCnt = 0; outCnt < 5; outCnt++) {
        /* 最初は data[outCnt] を最大値と仮定して考えるので、
           max には ourCnt の値をセットする。 */
        max = outCnt;

        /* inCnt には outCnt + 1 をセットする。 */
        for (inCnt = outCnt + 1; inCnt < 5; inCnt++) {
            /* 最大値が格納されている要素番号を見つける。 */
            if (data[max] < data[inCnt]) {
                max = inCnt;
            }
        }

        /* このif文は無くても動く */
        if (outCnt != max) {
            temp = data[outCnt];
            data[outCnt] = data[max];
            data[max] = temp;
        }
    }

    printf("ソート後\n");
    printArray(data);
}

/* 配列の内容を表示するための関数 */
void printArray(int data[]) {
    int cnt;
    for (cnt = 0; cnt < 5; cnt++) {
        printf("data[%d]:%d\n", cnt, data[cnt]);
    }
}

初心者がもっとも躓きやすいポイントは、2つ目のループ処理の回し方です。

for (inCnt = outCnt + 1; inCnt < 5; inCnt++) 

初心者は「 inCnt = outCnt + 1 」を思いつけないことが多いです。
2つ目のループを0から回し始めると、以下のイメージのような判定が発生してしまうので、うまくソートできずに詰みます。

こうならないように、以下の点を覚えておいてください。
・現在位置から左側は既に順序が確定している。
・右側だけで比較すれば良い。

まとめ

今回は「選択ソート」のイメージとプログラムに落とし込む際の思考の流れを紹介しました。
選択ソートは
・最大値を探し出して、1つ目の要素と入れ替える。
・1つ目の最大値が判明したら、次の最大値を探し出して2つ目の要素と入れ替える。
・上記の流れを配列の数だけ繰り返すとソートが完成する。

プログラムにおいては
・二重ループが必要になる。
・変数が持つべきは「最大値」そのものではなく、「最大値が格納されている要素番号」。
・要素番号を元に入れ替えを行う。

選択ソートは、授業や新人研修などでもよく出てきますので、覚えておいて損は無いと思います。
特に新人研修でこれに躓くと「進捗が遅い=できない子」の評価になってしまうので、イメージを事前に頭に叩き込んで、サクッと突破しちゃいましょう!

では、本日はここまでにしたいと思います。
お疲れ様でした!

コメント

タイトルとURLをコピーしました