第24章 たのしいソート

 いきなりアホな題ですみません。まぁ、そういうわけで今回からはソートをやってみたいと思います。ソートというのは、データを順番に並べ替えることです。いろいろなところで使うことがあるでしょう。


 では、今回の要点をどうぞ。


 では、いってみましょう。


 データを順番通りに並び替えることをソートといい、いろいろなところで使われます。先ず今回は難しいことを考えず、心の赴くままにソートしてみます。

 次のようなデータがあるとします。

プログラム1
// SortData.cpp
#include "MainDefs.h"

// ソートするデータ
int g_anData[] = {
    117, 169,  99, 168,  48, 128,   1, 155,  39, 101,
     54, 150, 173, 174,   9,  76,  55,  77, 186, 213,
     16, 175,  14, 173,  78, 228, 231, 254,   4, 255,
     23,  34, 185, 192, 118,  99,  25, 112,  51,   6,
    235,  13, 103, 137,  67, 167, 240,  40, 249,  10,
    124, 166,  89, 157, 228,  73,  28, 138, 188,  39,
    152,  31,  40, 160,  51, 117, 240,  44,  29,  79,
    215,  87,  63,  68,  41,   9, 110,  33, 148,  11,
    229, 137,  56, 199, 242, 222,   1,  79, 239, 101,
     53, 161, 116, 164,  73,  42, 203,  15, 249, 136,
};

// ソートするデータの数
int g_nNumOf = numof(g_anData);
プログラム2
// SortData.h
#ifndef __SORTDATA_H__INCLUDED__
#define __SORTDATA_H__INCLUDED__

extern int g_anData[];  // ソートするデータ
extern int g_nNumOf;    // ソートするデータの数

#endif
プログラム3
// MainDefs.h
#ifndef __MAINDEFS_H__INCLUDED__
#define __MAINDEFS_H__INCLUDED__

// 配列の要素数を取得
#define numof(array)  (sizeof (array) / sizeof *(array))

#endif

 このデータ g_anData を小さい方から大きい方へとなるように並べ替えてみましょう。インデックスが増えるに連れて値が大きくなっていくので、このような順番を昇順と呼びます。その逆は降順です。

 簡単に考えると、データを全部見て一番大きいの最後に持っていき、次にそれを除いてデータを全部見てその中で一番大きいの最後から2番目に置く、というような作業を(データの個数−1)回すればいいですね。最後はデータが1個になるので、データの個数回まではする必要はありません。

 一番大きいものを探し最後に置くという操作は、次のようにすることができます。先ず、頭の方から隣同士のデータを比較していきます。そして右の方(インデックスの大きい方)が大きいときはそのまま放っておき、左の方(インデックスの小さい方)が大きいときはデータを交換します。これを続けていくと、一番大きいデータが一番右にやってきますね

 次は範囲を1つ狭めて、また頭から比較していきます。同じようにやっていくと、今度は次に大きいデータが右から2番目にやってきますね。これを続けていくとデータをソートすることができます。

 これを図にすると、下図のようになります。

最も単純なソートアルゴリズム
図.1 最も単純なソートアルゴリズム

 一番大きいデータが泡が昇っていくかのように浮き出てくるので、このソート方法をバブルソートと呼びます。

 ということでプログラムを組んでみましょう。

プログラム1
// SortSub.h
#ifndef __SORTSUB_H__INCLUDED__
#define __SORTSUB_H__INCLUDED__

// 値の入れ替え
// temp 変数を仲介に、temp ← a ← b ← temp と
// データを移せば入れ替え完了です
inline void Swap(int& a, int& b)
{
    int temp;
    temp = a;
    a = b;
    b = temp;
}

// 配列の表示
void DispArray(const int* pnData, int nNumOf);

#endif
プログラム2
// SortSub.cpp
#include <stdio.h>

void DispArray(const int* pnData, int nNumOf)
{
    const int PER_LINE = 10;  // 1行に表示する数
    int i;

    for(i = 0; i < nNumOf; i++)
    {
        // %3d の 3 は、最低3文字表示するという意味です
        // 1のときは "  1" というように、左に空白が入ります
        printf("%3d, ", pnData[i]);
        if(i % PER_LINE == PER_LINE - 1)
            putchar('\n');
    }
}
プログラム3
// Sort1.cpp
#include "SortData.h"
#include "SortSub.h"

// バブルソート
void BubbleSort(int* pnData, int nNumOf)
{
    int iLoop;  // (データの個数−1)回回すための変数
    int iComp;  // 比較するときのループ変数

    // (データの個数−1)回回します
    // 上の図を見れば、この回数も納得がいくでしょう
    for(iLoop = 0; iLoop < nNumOf - 1; iLoop++)
    {
        // 比較を行い、大きい方のデータを左に持っていきます
        // 初めは(データの個数−1)回で、一週毎に回数が減っていきます
        for(iComp = 0; iComp < nNumOf - 1 - iLoop; iComp++)
        {
            // 比較して、左の方が大きければ交換
            if(pnData[iComp] > pnData[iComp + 1])
                Swap(pnData[iComp], pnData[iComp + 1]);
        }
    }
}

int main()
{
    BubbleSort(g_anData, g_nNumOf);
    DispArray(g_anData, g_nNumOf);

    return 0;
}
実行結果
  1,   1,   4,   6,   9,   9,  10,  11,  13,  14,
 15,  16,  23,  25,  28,  29,  31,  33,  34,  39,
 39,  40,  40,  41,  42,  44,  48,  51,  51,  53,
 54,  55,  56,  63,  67,  68,  73,  73,  76,  77,
 78,  79,  79,  87,  89,  99,  99, 101, 101, 103,
110, 112, 116, 117, 117, 118, 124, 128, 136, 137,
137, 138, 148, 150, 152, 155, 157, 160, 161, 164,
166, 167, 168, 169, 173, 173, 174, 175, 185, 186,
188, 192, 199, 203, 213, 215, 222, 228, 228, 229,
231, 235, 239, 240, 240, 242, 249, 249, 254, 255,

 はい、ソートできました。

 このソート方法は最も単純なものです。そして、最も遅い方法です。

 しかし、データ数が少ないときは充分実用できます。ソート関数を自作して使いたいときは、簡単に作れる(=バグの出にくい)バブルソートを使ってもいいでしょう。

 他にも色々なソート方法が開発されています。それについては...次回以降にお話ししたいと思います。


 では、今回の要点です。


 それでは、次回まで。


第23章 call itself 3 | 第25章 たのしいソート2

Last update was done on 2000.9.13

この講座の著作権はロベールが保有しています