HSP3 プログラミングの基礎W
前へ 目次へ 次へ 

(4) 並べ替え(sort : ソート)

 ソートとは、複数あるデータを特定の基準にしたがって並べる順番を替えることである。
 今、20, 70, 40, 80, 30の5つのデータがあるとする。これを並べ替えて80, 70, 40, 30, 20としたとき、データを大きい順(昇順(ショウジュン)という)にソートしたことになる。また、20, 30, 40, 70, 80としたとき、データを小さい順(降順(コウジュン)という)にソートしたことになる。
 文字データの場合、文字には1文字ずつ番号(文字コードという)が割り当てられているので、その文字コード順に並べ替えられる。

文字コード表
文字コード表

 ソートの計算方法(アルゴリズムという)にはいろいろなものがあるが、ここでは直接選択法でソートする。

 


ソート(直接選択法)

サンプル配列に格納した整数のデータを直接選択法で昇順にソートする。

    ;データ設定
    dim data, 10
    sdim data1
    data =  4, 2, 8, 6, 1, 10, 7, 9, 3, 5
    foreach data
        data1 = data1 + "[" + data(cnt) + "] "
    loop
    mes "元のデータ" + data1
    ;ソート処理
    repeat length(data) - 1
        d1 = cnt
        repeat length(data) - (d1 + 1), d1 + 1
            if data(d1) > data(cnt){    ;データ比較 
                work = data(d1)
                data(d1) = data(cnt)
                data(cnt) = work
            }
        loop
    loop
    ;結果表示
    data1 = ""
    foreach data
        data1 = data1 + "[" + data(cnt) + "] "
    loop
    mes "昇順データ" + data1
    stop

実行次のように、昇順(小さい順)で表示される。

元のデータ[4] [2] [8] [6] [1] [10] [7] [9] [3] [5]
昇順データ[1] [2] [3] [4] [5] [6] [7] [8] [9] [10]
☆直接選択法(昇順の場合)
 
 データの並びの先頭(0番)と2つ目(1番)以降のデータとを順番に比較し、先頭(0番)のデータの方が大きければデータを入れ替える。すべての比較が終わった時点で先頭(0番)には最も小さいデータが格納されていることになる。これで、先頭(0番)のデータは確定である。
 ( )内の数字は配列の添え字である。
 次に、2つ目(1番)と3つ目(2番)以降のデータとを順番に比較し、2つ目(1番)のデータの方が大きければデータを入れ替える。すべての比較が終わった時点で2つ目(1番)には2つ目以降のデータの中で最も小さいデータが格納されていることになる。これで、2つ目(1番)のデータは確定である。
 以降、3つ目(2番)と4つ目(3番)以降のデータ、4つ目(3番)と5つ目(4番)以降のデータ、…、8つ目(7番)と9つ目(8番)以降のデータとを順番に比較してデータを入れ替えていく。
 
 最後に、9つ目(8番)と10個目(9番)のデータを比較してデータを入れ替えていく。
 
0と1
0と2

0と9
番の比較
1と2
1と3
 …
1と9
番の比較
7と8
7と9
番の比較
8と9 番の比較
○と△ 番の比較
 左表のように、配列の○番と△番の値を比較していく。
 ○番は、0, 1, 2, 3, 4, 5, 6, 7, 8 と変化していく。repeat命令の繰り返し回数は、「配列の個数−1」である。システム変数cntの値が使える。
 △番は、○+1, …, 9 と変化していく。repeat命令の繰り返し回数は、「配列の個数−(○+1)」である。システム変数cntの値は○+1で初期化して使う。
 
 次のプログラムは、先頭と2番目以降のデータ、2番目と3番目以降の
データ、…を比較した結果を表示するサンプルである。
実行
    ;データ設定
    dim data, 10
    sdim data1
    data = 4, 2, 8, 6, 1, 10, 7, 9, 3, 5
    foreach data
        data1 = data1 + "[" + data(cnt) + "] "
    loop
    mes "元のデータ" + data1
    ;ソート処理
    mes "途中経過"
    repeat length(data) - 1
        d1 = cnt
        repeat length(data) - (d1 + 1), d1 + 1
            if data(d1) > data(cnt){    ;データ比較
                work = data(d1)
                data(d1) = data(cnt)
                data(cnt) = work
            }
        loop
        gosub *hyouji
    loop
    mes "ソート結果"
    gosub *hyouji
    stop
    ;結果表示
*hyouji
    data1 = ""
    foreach data
        data1 = data1 + "[" + data(cnt) + "] "
    loop
    mes "昇順データ" + data1
    return
    stop
元のデータ[2] [1] [6] [8] [10] [7] [9] [3] [4] [5]
途中経過
昇順データ[1] [4] [8] [6] [2] [10] [7] [9] [3] [5]
昇順データ[1] [2] [8] [6] [4] [10] [7] [9] [3] [5]
昇順データ[1] [2] [3] [8] [6] [10] [7] [9] [4] [5]
昇順データ[1] [2] [3] [4] [8] [10] [7] [9] [6] [5]
昇順データ[1] [2] [3] [4] [5] [10] [8] [9] [7] [6]
昇順データ[1] [2] [3] [4] [5] [6] [10] [9] [8] [7]
昇順データ[1] [2] [3] [4] [5] [6] [7] [10] [9] [8]
昇順データ[1] [2] [3] [4] [5] [6] [7] [8] [10] [9]
昇順データ[1] [2] [3] [4] [5] [6] [7] [8] [9] [10]
ソート結果
昇順データ[1] [2] [3] [4] [5] [6] [7] [8] [9] [10]
 
 
 
参考 ソートのアルゴリズム

試してみよう降順にソートする。

 元のサンプルで、※印の行にある比較演算子を">"から"<"に変更するだけである。

            if data(d1) > data(cnt){    ;データ比較 
            ↓
            if data(d1) < data(cnt){    ;データ比較 

実行次のように、降順(大きい順)で表示される。

元のデータ[2] [1] [6] [8] [10] [7] [9] [3] [4] [5]
降順データ[10] [9] [8] [7] [6] [5] [4] [3] [2] [1]

 


データの交換命令(swap)作成 - #define

 2つの変数に格納されている値を入れ替える命令を作成する。サンプルのプログラムでは、配列data(d1)とdata(cnt)の値を入れ替えている次の部分の処理である。

    work = data(d1)
    data(d1) = data(cnt)
    data(cnt) = work

 #deffuncで命令を定義すると次のようになる。

#deffunc swap int a, int b
    work = a
    a = b
    b = work
    return

 しかし、このswap命令はパラメータとしてint型のデータを受け取るので実数や文字列を交換することができない。
 ここでは、#defineで命令を定義することにする。#defineは「#define  A  B」の形で書き、プログラムの中に「A」があれば「B」に置き換えてくれる。例えば次のように書く。

#define  hello  mes "Hello"

 プログラム中の「hello」と書かれた部分は、実行するときに「mes "Hello"」と置き換えられる。
 パラメータも%1, %2,…で設定することもできる。例えば次のように書く。

#define  display(%1)  mes %1

 プログラム中の「display  "HSP Programming"」と書かれた部分は、実行するときに「mes "HSP Programming"」と置き換えられる。
 #defineの後にglobalを書けば、すべてのモジュール内で有効になる。

サンプルデータの交換命令(swap)を#defineで作成する。

#define global swap(%1, %2) _wk = %1 : %1 = %2 : %2 = _wk
    ;データ設定
    dim data, 10
    sdim data1
    data =  4, 2, 8, 6, 1, 10, 7, 9, 3, 5
    foreach data
        data1 = data1 + "[" + data(cnt) + "] "
    loop
    mes "元のデータ" + data1
    ;ソート処理
    repeat length(data) - 1
        d1 = cnt
        repeat length(data) - (d1 + 1), d1 + 1
            if data(d1) > data(cnt) : swap data(d1), data(cnt)    ;データ比較
        loop
    loop
    ;結果表示
    data1 = ""
    foreach data
        data1 = data1 + "[" + data(cnt) + "] "
    loop
    mes "昇順データ" + data1
    stop

実行次のように、昇順(小さい順)で表示される。

元のデータ[4] [2] [8] [6] [1] [10] [7] [9] [3] [5]
昇順データ[1] [2] [3] [4] [5] [6] [7] [8] [9] [10]

 


ソート命令(sort_num)作成

 配列に格納された整数または実数のデータをソートする命令sort_numを作成する。ソートの結果は元の配列に格納される。

サンプルソートする命令sort_numを作成する。パラメータは配列と昇順・降順を指示するデータとする。

#define global swap(%1, %2) _wk = %1 : %1 = %2 : %2 = _wk
#module
#deffunc sort_num array dd, int flag
;
;sort_num  配列変数, flag
;  flag=0:昇順、1:降順
;  配列変数の内容が書き換えられる。
;
    repeat length(dd) - 1
        d1 = cnt
        repeat length(dd) - (d1 + 1), d1 + 1
            if flag = 0 & dd(d1) > dd(cnt) : swap dd(d1), dd(cnt)
            if flag = 1 & dd(d1) < dd(cnt) : swap dd(d1), dd(cnt)
        loop
    loop
    return
#global
    ;データ設定
    dim data, 10
    sdim data1
    data = 4, 2, 8, 6, 1, 10, 7, 9, 3, 5
    mes "元のデータ"
    gosub *hyouji
    ;ソート処理
    sort_num data, 0    ;昇順
    mes "昇順ソート結果"
    gosub *hyouji
    sort_num data, 1    ;降順
    mes "降順ソート結果"
    gosub *hyouji
    stop
    ;結果表示
*hyouji
    data1 = ""
    foreach data
        data1 = data1 + "[" + data(cnt) + "] "
    loop
    mes data1
    return
    stop

実行次のように、昇順と降順の結果が表示される。

元のデータ
[4] [2] [8] [6] [1] [10] [7] [9] [3] [5]
昇順ソートの結果
[1] [2] [3] [4] [5] [6] [7] [8] [9] [10]
降順ソートの結果
[10] [9] [8] [7] [6] [5] [4] [3] [2] [1]

 パラメータの配列は一次元に限る。
 一次元配列はa(n)、二次元はa(n1,n2)、と書き方が違うのでこの命令では一次元配列のデータしかソートできない。

 

サンプルハイスコア10人分の処理を行う。データは得点と名前とする。

#define global swap(%1, %2) _wk = %1 : %1 = %2 : %2 = _wk
#module
#deffunc sort_score array dd, array na
    repeat length(dd) - 1
        d1 = cnt
        repeat length(dd) - (d1 + 1), d1 + 1
            if dd(d1) < dd(cnt) : swap dd(d1), dd(cnt) : swap na(d1), na(cnt)
        loop
    loop
    return
#global
    ;データ設定
    dim score, 11           ;得点
    sdim namae, 20, 11      ;名前
    sdim data1, , 2
    score = 4444, 2222, 8888, 6666, 1111, 1010, 7777, 9999, 3333, 5555
    namae(0) = "A男", "B男", "C子", "D男", "E子"
    namae(5) = "F男", "G子", "H男", "I子", "J男"
    mes "元のデータ"
    gosub *hyouji
    ;ソート処理
    sort_score score, namae
    mes "ソート結果1"
    gosub *hyouji
    score(10) = 10000 : namae(10) = "K子"
    sort_score score, namae
    mes "ソート結果2"
    gosub *hyouji
    stop
    ;結果表示
*hyouji
    data1(0) = ""
    data1(1) = ""
    repeat 5
        data1(0) = data1(0) + "[" + score(cnt) + " " + namae(cnt) + "] "
        data1(1) = data1(1) + "[" + score(cnt + 5) + " " + namae(cnt + 5) + "] "
    loop
    mes data1(0)
    mes data1(1)
    return
    stop
実行
元のデータ
[4444 A男] [2222 B男] [8888 C子] [6666 D男] [1111 E子]
[1010 F男] [7777 G子] [9999 H男] [3333 I子] [5555 J男]
ソート結果1
[9999 H男] [8888 C子] [7777 G子] [6666 D男] [5555 J男]
[4444 A男] [3333 I子] [2222 B男] [1111 E子] [1010 F男]
ソート結果2
[10000 K子] [9999 H男] [8888 C子] [7777 G子] [6666 D男]
[5555 J男] [4444 A男] [3333 I子] [2222 B男] [1111 E子]

 かなりの変更が必要である。
 名前を記録する配列変数namaeのデータ格納でnamae(0)="A男", …としている。これでnamae(0),namae(1),namae(2),…と順に代入される。同じように、namae(5)="F男",…でnamae(5),namae(6),namae(7),…と順に代入される。
 1つ目の結果は代入データを得点でソートしている。
 2つ目の結果は、新たに得点を配列の11番目に追加してからソートしている。

 

前へ 目次へ 次へ 
2006  © Hiroshi Masuda 

 

 

inserted by FC2 system