バブルソート



ソートとは並べ替えの事です。
そしてバブルソートとは、おそらく最も簡単な方法です。が、バブルソートは並べ替える要素の数が多いと、処理速度が遅くなります。
バブルソートはあまり数の多いものを並べ替えるのには向いていません。たくさんの要素を並べ替える方法としてはクイックソートというのがありますが、難しいので今回は取り上げません。

;バブルソートモジュール(数値・文字列双方対応。1次元配列のみ)
;bsort 配列変数,モード(0=小さい順,1=大きい順)

#module

#deffunc bsort val,int
	mref pval,1024	;PVAL構造体の取得
	mref mode,1	;モード取得
	if pval.0=4 {	;配列が数値型変数の場合
		mref elem,48	;数値型配列変数として取得
		repeat pval.2-1
			repeat pval.2-cnt-1
				c=cnt+1	;隣の番号
				if ((mode=0)&(elem.cnt>elem.c))|((mode=1)&(elem.cnt<elem.c)) {
					dummy=elem.cnt
					elem.cnt=elem.c
					elem.c=dummy
				}
			loop
		loop
	} else {	;配列が文字列型変数の場合
		mref elem,56	;文字列型配列変数として取得
		stackmax=50	;スタックの最大(高い方がいい)
		stack=0		;現在のスタック数
		dim startp,stackmax	;開始番号格納変数
		dim endp,stackmax	;終了番号格納変数
		startp.0=0	;最初の要素
		endp.0=pval.3-1	;最後の要素
		dim byte,stackmax	;何バイト目比較するか
		repeat
			stren=0	;連続開始番号
			front=0	;前のコード
			ren=0	;連続個数
			repeat endp.stack-startp.stack
				repeat endp.stack-startp.stack-cnt
					c=cnt+startp.stack
					c2=c+1
					peek code,elem.c,byte.stack	;文字コード読み出し
					peek code2,elem.c2,byte.stack	;隣も文字コード読み出し
					if ((mode=0)&(code>code2))|((mode=1)&(code<code2)) {
						dummy=elem.c
						elem.c=elem.c2
						elem.c2=dummy
					}
				loop
			loop
			repeat endp.stack-startp.stack+1
				c=startp.stack+cnt
				peek code,elem.c,byte.stack
				if code=0 : continue
				if code=front {
					ren++	;連続数+
				} else {
					if ren>0 {
						startp.stack=stren	;スタックに積む
						endp.stack=c-1		;スタックに積む
						byte.stack++	;次バイトへ
						stack++	;スタックを増やす
					}
					stren=c
					ren=0
					front=code
				}
			loop
			if ren>0 {
				startp.stack=stren	;スタックに積む
				endp.stack=c		;スタックに積む
				byte.stack++	;次バイトへ
				stack++	;スタックを増やす
			}
			stack--	;スタックを1減らす
			if stack=-1 : break	;スタックがなくなったら終了
		loop
	}
return

#global

;テスト
	;数値型配列
	imax=20
	dim suji,imax
	suji=0,2,5,9,7,6,3,4,8,1,16,564,65,465,46,145,46,4854,651,31
	pos 0,0 : mes "数値型:元の並び"
	repeat imax
		mes "suji."+cnt+"="+suji.cnt
	loop
	bsort suji
	pos 150,0 : mes "数値型:ソート後"
	repeat imax
		mes "suji."+cnt+"="+suji.cnt
	loop

	;文字列型
	smax=20
	sdim moji,10,smax
	moji="cls","bmpsave","pos","mes","color","boxf","font","dialog","continue","repeat","dim","sdim","goto","picload","screen","buffer","peek","poke","palcopy","mesbox"
	pos 300,0 : mes "文字列型:元の並び"
	repeat smax
		mes "moji."+cnt+"="+moji.cnt
	loop
	bsort moji
	pos 450,0 : mes "文字列型:ソート後"
	repeat smax
		mes "moji."+cnt+"="+moji.cnt
	loop
	stop

デバッグに2時間近くかかった…。
文字列の方はあまり考えないでください。自分でも作ってるうちになんか意味不明になってしまったので、解説できません。
まずPVAL構造体、配列の数を取り出すのに使用しています。構造体については「HSPからのDLL呼び出し方法リファレンスマニュアル」で詳しく書かれていますが、ここでも少しだけ解説しておきます。
PVAL構造体というのは変数の情報を格納している特殊な変数です。ここには変数の型や配列の情報などが詰まっています。
mref pval,1024とするとpvalは配列変数となり、それぞれの情報が要素ごとに格納され、取り出すことが出来るようになります。
配列数を取り出すとき、数値型変数の場合はpval.2に1次元目、pval.3に2次元目、pval.4に3次元目、pval.5に4次元目というように格納されています。
文字列型変数の場合、pval.3に1次元目となりpval.6まで。この数値型と文字列型の違いは何かというと、文字列では、pval.2にはどうやらメモリサイズが格納されているようです。
その変数が数値型であるか文字列型であるかを確認するにはpval.0でわかります。pval.0の値が4ならば、数値型変数であり、値が2ならば文字列型変数ということになります。
さて、バブルソートのアルゴリズムですが、考え方は簡単です。小さい順の場合、一つ目の要素から最後の要素までで、もっとも大きいものが最後に来るようにします。
その方法は、ある要素とその次の要素を見て、ある要素の値の方が大きかったらその二つの内容を入れ替えるということを繰り返します。
これを最初から最後までやっていけば、もっとも大きい値が最後に来るはずです。 これを繰り返せば、ちゃんとソートされます。


戻る