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, 2, 3, 4, 5, 6, 7, 8 と変化していく。repeat命令の繰り返し回数は、「配列の個数−1」である。システム変数cntの値が使える。 △番は、○+1, …, 9 と変化していく。repeat命令の繰り返し回数は、「配列の個数−(○+1)」である。システム変数cntの値は○+1で初期化して使う。
|
降順にソートする。
元のサンプルで、※印の行にある比較演算子を">"から"<"に変更するだけである。
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 |