■ ソート (File: plc_public_codex_xxx | Module:Sort)

⇒ TO Home Page
内容

PLC にはソート命令が備わっている機種もありますが、ここではSTG〜JMP命令のサンプルを兼ねて実装します。
1スキャン毎実行するのでスキャンタイムオーバは発生しませんが、処理時間がかかります。

次に挙げるアルゴリズムのサンプルがあります。
・シェーカーソート (Shaker Sort)
・奇偶転置ソート (Odd-even Sort)

デフォルトのソート対象要素数:50(設定範囲:10〜10000 変数[Element]にて変更可能)
ソート対象デバイス:BANK3 FM (FM0〜FM10000を ”Sort_Data[xxxx]”としてラベル定義)
デフォルトの実験用データ生成範囲:1〜256 (設定範囲:1〜65535 変数[AREA]にて変更可能)

●PDFを表示 
◆ シェーカーソート (Shaker Sort)

バブルソートで1回スキャンを行う と、最後の要素1個がスキャン範囲中最大であることが分かり
次回のスキャン範囲を1狭めることができる。
さらに、このスキャンの最後で連続してm個の要素の交換が行われていなければ
そのm個についてはソート済みであることが分かるので、次回のスキャン範囲をm狭めることができる。
この工夫で、後半が殆ど整列済みのデータに対してバブルソートが高速に行えるようになる。
シェーカーソートはこれに加え、スキャン方向を毎回反転することにより、スキャン範囲を後方からだけではなく
前方からも狭めるようにしたものである。
挿入ソートのように、殆ど整列済みのデータに対しては高速に行うことができる。
(ウィキペディアより)

変数:
【INDEX_Top】:配列添え字の小さい方の位置
【INDEX_Bot】:配列添え字の大きい方の位置
【INDEX_Swap】:最後にデータ入替を行った位置
【COUNT_IDX】:ループカウンタ(比較位置)

00011
・インデックスの初期値を設定します。
・トリガ[@MR000]をセットすると、他に起動しているソートルーチンが無いかをチェック(サブルーチン9)し、なければ次を実行します。
・【INDEX_Top】に”0”、【INDEX_Bot】に”要素数[Element] - 1 ”を代入します。


00013
・順方向スキャンループルーチンです。初期値を設定します。
・【INDEX_Top】を【INDEX_Swap】と【COUNT_IDX】に代入します。
・[SPAN]は入替するデータの距離です。(1なら後隣どうし、2なら後ろ1飛ばした位置です)


00014
・大小比較です。
・サブルーチン側では、【COUNT_IDX】が[Z1]に【COUNT_IDX】 + 1 が[Z2]に代入され、大小を比較します。
・【Sort_Data:Z1】 > 【Sort_Data:Z2】ならデータを入替し、入替実行フラグ[F_SWAP]をセットします。
・入替が行われたら、【INDEX_Swap】に【COUNT_IDX】の値を代入します。


00016
・ループカウンタを進めます。比較終了条件、【COUNT_IDX】≧【INDEX_Bot】でループを抜けます。
・最後の入替が行われた位置【INDEX_Swap】を【INDEX_Bot】に代入します。


00018
・【INDEX_Top】= 【INDEX_Bot】ならソートを完了します。
・【INDEX_Top】≠ 【INDEX_Bot】なら逆方向スキャンへ飛びます。


00021
・逆方向スキャンループルーチンです。初期値を設定します。
・【INDEX_Bot】を【INDEX_Swap】と【COUNT_IDX】に代入します。
・[SPAN]は入替するデータの距離です。(-1なら前隣どうし、-2なら前に1飛ばした位置です)


00022
・大小比較です。
・サブルーチン側では、【COUNT_IDX】が[Z1]に【COUNT_IDX】 - 1 が[Z2]に代入され、大小を比較します。
・【Sort_Data:Z1】 < 【Sort_Data:Z2】ならデータを入替し、入替実行フラグ[F_SWAP]をセットします。
・入替が行われたら、【INDEX_Swap】に【COUNT_IDX】の値を代入します。


00024
・ループカウンタを進めます。比較終了条件、【COUNT_IDX】 ≦ 【INDEX_Top】でループを抜けます。
・最後の入替が行われた位置【INDEX_Swap】を【INDEX_Top】に代入します。


00026
・【INDEX_Top】= 【INDEX_Bot】ならソートを完了します。
・【INDEX_Top】≠ 【INDEX_Bot】なら順方向スキャンへ飛びます。


00028
・ソートを完了したら、トリガをリセットして最初に戻ります。


00051
・入 替実行フラグ[F_SWAP]は他のアルゴリズムでも使用していますので、モジュールの最後でリセットします。


◆ テスト操作

・9行目でチェックしてください。
・[乱数生成] / [乱数転写] にカーソルを合わせ、ダブルクリックすると、ON-OFFできます。
・[乱数生成]は、乱数を[@FM0]〜 [Element]個分生成します。
・[乱数転写]は、[乱数生成]で生成した乱数を、ソート対象の[FM0]〜 に転送します。
・再度同じ要素でソートする場合は、[乱数転写]で同じ要素を転送します。
・[@MR000]をセットすると実行します。

◆ 奇偶転置ソート (Odd-even Sort)

奇偶置換ソートは、奇数番目とその次の偶数番目をペア (Pair1) にして比較/交換した後、
偶数番目とその次の奇数番目をペア(Pair2) にして比較/交換することを繰り返すアルゴリズムである。
Pair1:(1番目と2番目を比較、3番目と4番目を比較、5番目と6番目を比較、…)の後に
Pair2:(2番目と3番目を比較、4番目と5番目を比較、6番目と7番目を比較、…)を行う。これを繰り返す。
(ウィキペディアより)

変数:
 [FLAG]:
【BRAKE】:
COUNT_IDX】: ループカウンタ(比較位置)

00035
・ループの終了条件と入 替するデータの距離[SPAN] を設定します。
・ トリガ[@MR001]をセットすると、他に起動しているソートルーチンが無いかをチェック(サブルーチン9)し、なければ次を実行します。
・ソート未完了フラグ[FLAG]をセットします。
・偶数/奇数ループを抜ける条件【BRAKE】に”要素数[Element] - 2 ”を代入します。


00036
・未完了フラグ[FLAG]が偽(ソート完了)ならトリガ[@MR001]をリセットし、最初に戻ります。
・未完了フラグが真ならフラグをリセットして、【COUNT_IDX】を”0”に初期化します。(偶数)
・フラグで分岐する場合、同”STG”で真のフラグをリセットする (フラグの状態を変える)のは後に記述 してください。
(この例では、36行と37行を入替た記述はしないでください。 フラグが真の時、両方の条件が成立 します。)


00039
・偶数ペア大小比較です。
・サブルーチン側では、【COUNT_IDX】が[Z1]に【COUNT_IDX】 + 1 が[Z2]に代入され、大小を比較します。
・【Sort_Data:Z1】 > 【Sort_Data:Z2】ならデータを入替し、入替実行フラグ[F_SWAP]をセットします。
・入替が行われたら、未完了フラグをセットします。


00041
・ループカウンタを進めますが、偶数にするため+2しています。
・比較終了条件、【COUNT_IDX】 > 【BRAKE】でループを抜けます。
・比較が最後まで達していない時は比較ルーチンへ戻ります。

00044
・【COUNT_IDX】を”1”に初期化します。(奇数)


00045
・ 奇数ペア大小比較です。
・サブルーチン側では、【COUNT_IDX】が[Z1]に【COUNT_IDX】 + 1 が[Z2]に代入され、大小を比較します。
・【Sort_Data:Z1】 > 【Sort_Data:Z2】ならデータを入替し、入替実行フラグ[F_SWAP]をセットします。
・入替が行われたら、未完了フラグをセットします。


00047
・ループカウンタを進めますが、奇数にするため+2しています。
・比較終了条件、【COUNT_IDX】 > 【BRAKE】でループを抜けてソート未完了フラグをチェックします。
・比較が最後まで達していない時は比較ルーチンへ戻ります。


00051
・入替実行フラグ[F_SWAP]は他のアルゴリズムでも使用していますので、モジュールの最後でリセットします。

◆ 比較、入替サブルーチン

□1 . 昇順
00065
・[Sort_Data:Z1] > [Sort_Data:Z2]ならサブルーチン40を呼び出し、データを入替します。


□2 . 降順
00061
・[Sort_Data:Z1] < [Sort_Data:Z2]ならサブルーチン40を呼び出し、データを入替します。


□3 . データ入替
00057
・入替実行フラグ[F_SWAP]をセットします。
・[Sort_Data:Z1] と [Sort_Data:Z2]の値を入替ます。


◆ テスト操作

・33行目でチェックしてください。
・[乱数生成] / [乱数転写] にカーソルを合わせ、ダブルクリックすると、ON-OFFできます。
・[乱数生成]は、乱数を[@FM0]〜 [Element]個分生成します。
・[乱数転写]は、[乱数生成]で生成した乱数を、ソート対象の[FM0]〜 に転送します。
・再度同じ要素でソートする場合は、[乱数転写]で同じ要素を転送します。
・[@MR001]をセットすると実行します。

◆ 乱数生成、転送ルーチン

□1 . 乱数生成
00082
00083
・乱数関数で乱数を発生させます。(SEEDの初期値は1)

00084
・乱数を1〜[AREA]の範囲で生成します。
・生成される乱数範囲の 1〜65535 を 1〜[AREA] の範囲に変換します。
・変換後の値が”0”ではなかったら[@FM0:Z1]に代入し、Z1をカウントアップします。
・生成個数が要素数に達するまで、82行目にジャンプし、繰り返します。
・全ての乱数が生成されると、サブルーチンを抜けます。


□1 . 乱数転送
00076
・乱数生成で[@FM0]〜に書込まれた数値を、ソート対象の[FM0]〜に転送します。
・[FM0]〜最大個数分をクリアします。
・[@FM0]〜のデータを[FM0]〜に転送します。

●PDFを表示