はじめに
本記事シリーズは母国語のプログラミング言語が存在するという文化的価値をアピールするためのもので、プログラミング一般の入門を意図するものではありません。題材としては定番アルゴリズム:クイックソートを疑似言語ではなくコンパイル・実行可能なプログラミング言語の日本語で書いてみようというたてつけとなります。日本語プログラミング言語はドリトルを使用してみます。
ドリトル
ドリトルは、日本語に近い語順で記述できる、プロトタイプベースのオブジェクト指向の中間コードコンパイラ言語です。中間コードはJVMバイトコードで、Javaアプリケーションと同じ実行環境で動きます。また、教育目的で開発された日本語プログラミング言語であり、中学校・高校の教科書や副教材などに採用されています。語順はSOV型の日本語語順ですが(一部中置記法もあり)、単語間の分かち書きが必須であくまで形式言語です。
ドリトルの入手方法
ドリトルバージョン3(Windows版)を下記の公式サイトからダウンロードできます。
定番アルゴリズム:クイックソートとは
アルゴリズムは、問題を解決するための手順や計算方法を意味します。ソート(整列・並べ替え)はデータの並び順を特定の条件で並べ替えるためのアルゴリズムで、いくつかの定番ロジックが存在します。
ここではその中のひとつクイックソートを扱ってみます。クイックソートは適当な基準値(ピボット)を選び、その基準値を基にデータを小さい方と大きい方に分けることから始め、このプロセスを再帰的に繰り返すことで全体を整列させるロジックです。平均的には非常に高速で大規模なデータセットにも適しているとされていますが、ピボットの選択により計算量は変動します。
プログラミングの3大ロジック構造とは
順次、分岐、反復の3つの制御構造(control structures)によって処理の流れを記述することを構造化プログラミングといいます。挿入ソートもこの構造で構成されます。
1.順次(sequence) 部分プログラムを順々に実行する。
2.分岐(bifurcation) 条件式が導出した状態に従い、次に実行する部分プログラムを選択して分岐する。
3.反復(repetition) 条件式が導出した特定の状態の間、部分プログラムを繰り返し実行する。ループ処理。
お題のソースコード
並べ替え対象のデータ群には15の要素を持つ「配列」という特殊な整数型の変数を用意します。
段ボール箱が15あり、その中に小さなボールが複数づつ入っている状態をイメージしてください。段ボール箱は1つづつ15並んでいるのではなく、1つの長い段ボール箱が15のセクションで区切られているようなイメージが配列に近いです。ボールの数はおおむね右から左に向かって多くなり、同じ数が格納されていることはないとします。
ドリトルの場合、15の要素数の段ボール箱の配列要素番号は1からはじまり15で終わります。
まず、配列の中から1つの要素をピボットとして選びます。今回の例では左端の要素をピボットの初期値とします。そのピボットを基準に、配列を2つの部分配列に分割します。左側にはピボット以下の要素、右側にはピボットより大きい要素が配置されます。
各部分配列に対して同様の操作を行い、最終的に全ての要素が整列されるまで繰り返します。
段ボール箱=配列!17 18 19 21 15 14 13 12 3 10 9 8 7 6 5 作る。
改行コード = (0x0d!コード文字) + (0x0a!コード文字)。
表示エリア=テキストエリア!("")作る 900 500 大きさ 16 文字サイズ 。
表示エリア:改行してから表示する=「|s1 s2|
s1=s1+""。
「(s1!長さ? ) ==1」!
なら 「自分!(改行コード+s2+s1+s2) 書く。」
そうでなければ 「自分!(改行コード+s1+s2) 書く。」実行。
」。
表示エリア:表示する=「|s1 s2|
s1=s1+""。
「(s1!長さ? ) ==1」!
なら 「自分!(s2+s1+s2) 書く。」
そうでなければ 「自分!(s1+s2) 書く。」実行。
」。
段ボール箱の数を表示する=「
「|回数|
「(回数) ==1」!
なら 「表示エリア!(回数) " " 改行してから表示する」
そうでなければ 「表示エリア!(回数) " " 表示する」実行。
」!(段ボール箱!要素数?)繰り返す。
」。
段ボール箱のボールの数を表示する=「
「|回数|
「(回数) ==1」!
なら 「表示エリア!(段ボール箱!(回数) 読む) " " 改行してから表示する」
そうでなければ 「表示エリア!(段ボール箱!(回数) 読む) " " 表示する」実行。
」!(段ボール箱!要素数?)繰り返す。
」。
段ボール箱の値を入れ替える=「
| 入替元要素番号 入替先要素番号
; 一時退避のボール数 |
一時退避のボール数 = 段ボール箱!(入替先要素番号) 読む。
段ボール箱!(入替先要素番号) (段ボール箱!(入替元要素番号) 読む) 上書き。
段ボール箱!(入替元要素番号) (一時退避のボール数) 上書き。
表示エリア!("要素番号"+(入替元要素番号)+"と"+(入替先要素番号)) "を入れ替えました" 改行してから表示する。
表示エリア!((段ボール箱!(入替先要素番号) 読む) + "入替先要素") "" 表示する。
表示エリア!((段ボール箱!(入替元要素番号) 読む) + "入替元要素") "" 表示する。
」。
段ボール箱をパーティショニングする=「
| 左側要素番号 右側要素番号
; 要素番号 ピボット ピボットの要素番号 外側打ち切り 打ち切り |
表示エリア!("パーティショニング 左側要素番号"+(左側要素番号)+"右側要素番号"+(右側要素番号)) "" 改行してから表示する。
ピボット = 段ボール箱!(左側要素番号) 読む。
要素番号 = 左側要素番号 + 1。
ピボットの要素番号 = 右側要素番号。
表示エリア!("パーティショニング ピボット"+(ピボット)+"パーティショニング 要素番号"+(要素番号)+"ピボットの要素番号"+(ピボットの要素番号)) "" 改行してから表示する。
外側打ち切り = 0。
「外側打ち切り != 1」!の間
「
打ち切り = 0。
「打ち切り != 1」!の間
「
「要素番号 <= 右側要素番号」!
なら 「
「(段ボール箱!(要素番号) 読む) <= ピボット」!
なら 「要素番号 = 要素番号 + 1。」
そうでなければ 「打ち切り = 1。」実行。
」
そうでなければ 「打ち切り = 1。」実行。
」実行。//繰り返す
打ち切り = 0。
「打ち切り != 1」!の間
「
「ピボットの要素番号 >= 左側要素番号」!
なら 「
「(段ボール箱!(ピボットの要素番号) 読む) > ピボット」!
なら 「ピボットの要素番号 = ピボットの要素番号 - 1。」
そうでなければ 「打ち切り = 1。」実行。
」
そうでなければ 「打ち切り = 1。」実行。
」実行。//繰り返す
表示エリア!("パーティショニング 増減ループ後:要素番号" + (要素番号) + ":ピボットの要素番号"+(ピボットの要素番号)) "" 改行してから表示する。
「要素番号 < ピボットの要素番号」!
なら「
「要素番号 != ピボットの要素番号」!
なら
「
ルート!(要素番号) (ピボットの要素番号) 段ボール箱の値を入れ替える。
表示エリア!(ピボットの要素番号) "パーティショニング:ピボットの要素番号" 改行してから表示する。
表示エリア!"パーティショニング:整列中" "" 改行してから表示する。
ルート!段ボール箱の数を表示する。
ルート!段ボール箱のボールの数を表示する。
」実行。
」
そうでなければ 「外側打ち切り = 1。」実行。
」実行。//繰り返す
「左側要素番号 != ピボットの要素番号」!
なら
「
ルート!(左側要素番号) (ピボットの要素番号) 段ボール箱の値を入れ替える。
表示エリア!"パーティショニング:整列中2" "" 改行してから表示する。
ルート!段ボール箱の数を表示する。
ルート!段ボール箱のボールの数を表示する。
」実行。
(ピボットの要素番号)。
」。
段ボール箱をクイックソートする=「
| 左側要素番号 右側要素番号
; ピボットの要素番号 |
「左側要素番号 < 右側要素番号」!
なら
「
ピボットの要素番号=ルート!(左側要素番号) (右側要素番号) 段ボール箱をパーティショニングする。
ルート!(左側要素番号) (ピボットの要素番号 - 1) 段ボール箱をクイックソートする。 //左側を再帰的にソート
ルート!(ピボットの要素番号 + 1) (右側要素番号) 段ボール箱をクイックソートする。 //右側を再帰的にソート
」実行。
」。
表示エリア!"並べ替え前の状態" "" 表示する。
ルート!段ボール箱の数を表示する。
ルート!段ボール箱のボールの数を表示する。
ルート!(1) (段ボール箱!要素数?) 段ボール箱をクイックソートする。
表示エリア!"並べ替え後の状態" "" 改行してから表示する。
ルート!段ボール箱の数を表示する。
ルート!段ボール箱のボールの数を表示する。
「段ボール箱をクイックソートする」が大枠再帰的にループを回しているロジックですが、実際に要素の入れ替えを行っているロジックは「段ボール箱をパーティショニングする」です。そしてさらに指定された要素の入れ替えを行う「段ボール箱の値を入れ替える」が直接入れ替えています。
この内部での入れ替え反復処理の動きがわかるようにピボットの要素番号などの中間変数の動きはコンソール出力しています。
ドリトルの場合、反復構文は回数指定反復か条件成立の間の反復の2つに制限されますので、ループ打ち切りの構文はないため、反復構文の条件式の変数をループ内の条件分岐で反転させて、疑似的に打ち切りのような処理を実装しています。
お題のソースコードをコンパイル・実行
では、コンパイル・実行してみます。実行環境はドリトル編集実行画面です。テキストエリアに出力しています。
並べ替え前の状態
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
17 18 19 21 15 14 13 12 3 10 9 8 7 6 5
パーティショニング 左側要素番号1右側要素番号15
パーティショニング ピボット17パーティショニング 要素番号2ピボットの要素番号15
パーティショニング 増減ループ後:要素番号2:ピボットの要素番号15
要素番号2と15を入れ替えました18入替先要素5入替元要素
15パーティショニング:ピボットの要素番号
パーティショニング:整列中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
17 5 19 21 15 14 13 12 3 10 9 8 7 6 18
パーティショニング 増減ループ後:要素番号3:ピボットの要素番号14
要素番号3と14を入れ替えました19入替先要素6入替元要素
14パーティショニング:ピボットの要素番号
パーティショニング:整列中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
17 5 6 21 15 14 13 12 3 10 9 8 7 19 18
パーティショニング 増減ループ後:要素番号4:ピボットの要素番号13
要素番号4と13を入れ替えました21入替先要素7入替元要素
13パーティショニング:ピボットの要素番号
パーティショニング:整列中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
17 5 6 7 15 14 13 12 3 10 9 8 21 19 18
パーティショニング 増減ループ後:要素番号13:ピボットの要素番号12
要素番号1と12を入れ替えました17入替先要素8入替元要素
パーティショニング:整列中2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
8 5 6 7 15 14 13 12 3 10 9 17 21 19 18
パーティショニング 左側要素番号1右側要素番号11
パーティショニング ピボット8パーティショニング 要素番号2ピボットの要素番号11
パーティショニング 増減ループ後:要素番号5:ピボットの要素番号9
要素番号5と9を入れ替えました15入替先要素3入替元要素
パーティショニング:ピボットの要素番号9パーティショニング:ピボットの要素番号
パーティショニング:整列中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
8 5 6 7 3 14 13 12 15 10 9 17 21 19 18
パーティショニング 増減ループ後:要素番号6:ピボットの要素番号5
要素番号1と5を入れ替えました8入替先要素3入替元要素
パーティショニング:整列中2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
3 5 6 7 8 14 13 12 15 10 9 17 21 19 18
パーティショニング 左側要素番号1右側要素番号4
パーティショニング ピボット3パーティショニング 要素番号2ピボットの要素番号4
パーティショニング 増減ループ後:要素番号2:ピボットの要素番号1
パーティショニング 左側要素番号2右側要素番号4
パーティショニング ピボット5パーティショニング 要素番号3ピボットの要素番号4
パーティショニング 増減ループ後:要素番号3:ピボットの要素番号2
パーティショニング 左側要素番号3右側要素番号4
パーティショニング ピボット6パーティショニング 要素番号4ピボットの要素番号4
パーティショニング 増減ループ後:要素番号4:ピボットの要素番号3
パーティショニング 左側要素番号6右側要素番号11
パーティショニング ピボット14パーティショニング 要素番号7ピボットの要素番号11
パーティショニング 増減ループ後:要素番号9:ピボットの要素番号11
要素番号9と11を入れ替えました15入替先要素9入替元要素
11パーティショニング:ピボットの要素番号
パーティショニング:整列中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
3 5 6 7 8 14 13 12 9 10 15 17 21 19 18
パーティショニング 増減ループ後:要素番号11:ピボットの要素番号10
要素番号6と10を入れ替えました14入替先要素10入替元要素
パーティショニング:整列中2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
3 5 6 7 8 10 13 12 9 14 15 17 21 19 18
パーティショニング 左側要素番号6右側要素番号9
パーティショニング ピボット10パーティショニング 要素番号7ピボットの要素番号9
パーティショニング 増減ループ後:要素番号7:ピボットの要素番号9
要素番号7と9を入れ替えました13入替先要素9入替元要素
パーティショニング:ピボットの要素番号9パーティショニング:ピボットの要素番号
パーティショニング:整列中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
3 5 6 7 8 10 9 12 13 14 15 17 21 19 18
パーティショニング 増減ループ後:要素番号8:ピボットの要素番号7
要素番号6と7を入れ替えました10入替先要素9入替元要素
パーティショニング:整列中2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
3 5 6 7 8 9 10 12 13 14 15 17 21 19 18
パーティショニング 左側要素番号8右側要素番号9
パーティショニング ピボット12パーティショニング 要素番号9ピボットの要素番号9
パーティショニング 増減ループ後:要素番号9:ピボットの要素番号8
パーティショニング 左側要素番号13右側要素番号15
パーティショニング ピボット21パーティショニング 要素番号14ピボットの要素番号15
パーティショニング 増減ループ後:要素番号16:ピボットの要素番号15
要素番号13と15を入れ替えました21入替先要素18入替元要素
パーティショニング:整列中2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
3 5 6 7 8 9 10 12 13 14 15 17 18 19 21
パーティショニング 左側要素番号13右側要素番号14
パーティショニング ピボット18パーティショニング 要素番号14ピボットの要素番号14
パーティショニング 増減ループ後:要素番号14:ピボットの要素番号13
並べ替え後の状態
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
3 5 6 7 8 9 10 12 13 14 15 17 18 19 21
かなり芸のない出力ですが、イメージわきましたでしょうか?一部ランダム降順だった数列が昇順に並び変わっていることがわかります。
おわりに
いかがでしたでしょうか?わたしはわが国に母語によるプログラミング言語が存在することを誇りに思っております。言語は文化。こんにちの日本語のポップスやアニメソングなどが海外でそのまま歌われるような近況を鑑みますと、純然たる技術基盤として超強力な米欧発プログラミング言語勢と存在意義を争うこともなく、日本語の文化として海外でも日本語プログラミング言語の愛される日が来るのやもしれません。