Web教材一覧>
アルゴリズム
(BOK大区分:1 基礎理論、中区分:2 アルゴリズムとプログラミング、中区分:2 アルゴリズム)
外部ソートとは、磁気ディスクや磁気テープに保管されているファイルをソートすることです。ここでは順編成ファイルを対象とします。マージ(併合)とは、既に共通のキー項目でソートされている2つのファイルあるいは配列を、ソートの順序を保持しながら1つのファイル(配列)にまとめる処理です。外部ソートを行うには、マージが重要な処理になります。
アルゴリズム、外部ソート、マージ
既にソートされている複数の配列やファイルを、ソートの順序を保持しつつ、一つの配列やファイルにまとめることをマージ(併合)といいます。
2つの順編成ファイル、ファイルBとファイルCが、それぞれコードBとコードCの昇順にソートされています。それをマージしてファイルAにするアルゴリズムを考えます。
ファイルB ファイルC ファイルA
コードB コードC
┌──┬─────┐ ┌──┬─────┐ ┌──┬─────┐
│10│BBアアア│ │20│CCカカカ│ ①│10│BBアアア│
├──┼─────┤ ├──┼─────┤ ├──┼─────┤
│30│BBイイイ│ │40│CCキキキ│ ②│20│CCカカカ│
├──┼─────┤ ├──┼─────┤ ├──┼─────┤
│40│BBウウウ│ │60│CCククク│ ③│30│BBイイイ│
└──┴─────┘ └──┴─────┘ ├──┼─────┤
:99:Bの終わり: :99:Cの終わり: ④│40│BBウウウ│
・……・……………・ ・……・……………・ ├──┼─────┤
⑤│40│CCキキキ│
├──┼─────┤
⑥│60│CCククク│
└──┴─────┘
アルゴリズム
一般的には、次のようになります。
コードB<コードC : ファイルBのレコードをファイルAにコピーして、次にファイルBを読む
コードB>コードC : ファイルCのレコードをファイルAにコピーして、次にファイルCを読む
コードB=コードC : ファイルBとCのレコードをファイルAにコピーして、次にファイルBとCを読む
ファイルのすべてのレコードを読み終わった後をどうすればよいでしょうか。
上図の点線のようなダミーレコードがあればよいと考えられます。このような機能は、例えばCOBOLでは
READ ファイルB AT END コードB=大きい値.
という機能があります。
プログラム
ア ファイルBを読む。終わりならば コードB=99;
イ ファイルCを読む。終わりならば コードC=99;
ウ while ( (コードB<99) and (コードC<99) ) {
エ if (コードB<コードC) {
オ レコードBをファイルAに出力;
カ ファイルBを読む。終わりならば コードB=99;
キ }
ク else if (コードB>コードC) {
ケ レコードCをファイルAに出力;
コ ファイルCを読む。終わりならば コードC=99;
サ }
シ else if (コードB>コードC) {
ス レコードBをファイルAに出力;
セ レコードCをファイルAに出力;
ソ ファイルBを読む。終わりならば コードB=99;
タ ファイルCを読む。終わりならば コードB=99;
チ }
ツ }
トレース
ア コードB=10
イ コードC=20
ウ コードB<99 コードC<99、 コードB(10)<コードC(20) → オへ
オ コードB(10)のレコードを出力 ①
カ コードB=30 → ウへ
ウ コードB<99 コードC<99、 コードB(30)>コードC(20) → ケへ
ケ コードC(20)のレコードを出力 ②
コ コードC=40 → ウへ
ウ コードB<99 コードC<99、 コードB(30)<コードC(40) → オへ
オ コードB(30)のレコードを出力 ③
カ コードB=40 → ウへ
ウ コードB<99 コードC<99、 コードB(40)=コードC(40) → スへ
ス コードB(40)のレコードを出力 ④
セ コードC(40)のレコードを出力 ⑤
ソ ファイルB終わり コードB=99
タ コードC=60 → ウへ
ウ コードB=99 しかし コードC<99、 コードB(99)>コードC(60) → ケへ
ケ コードC(60)のレコードを出力 ⑥
コ ファイルC終わり コードC=99 → ウへ
ウ コードB=99 AND コードC=99 → 終了
練習問題
<問題>
ファイルBとファイルCがソートされているとの条件に反しますが、次のファイルを、上のプログラムでマージすると、どのようになるでしょうか。
ファイルB ファイルC
コードB コードC
┌──┬─────┐ ┌──┬─────┐
│10│BBアアア│ │20│CCカカカ│
├──┼─────┤ ├──┼─────┤
│40│BBイイイ│ │60│CCキキキ│
├──┼─────┤ ├──┼─────┤
│30│BBウウウ│ │50│CCククク│
└──┴─────┘ └──┴─────┘
<解答>
┌──┬─────┐
│10│BBアアア│
├──┼─────┤
│20│CCカカカ│
├──┼─────┤
│40│BBイイイ│
├──┼─────┤
│30│BBウウウ│
├──┼─────┤
│60│CCキキキ│
├──┼─────┤
│50│CCククク│
└──┴─────┘
かなり複雑になりますが、入力ファイルが3つ以上でのマージを行うことも可能です。その機能をもつユーティリティソフトウェアが提供されています。
磁気ディスクや磁気テープなど、外部記憶装置にあるファイルをソートすることを外部ソートといいます。
ファイルの全データをメモリに読み込むことは、メモリ容量が不足しますので、外部記憶装置を用いてソートする必要があります。
直接編成ファイルや索引順編成ファイルなどに関しては、別章で取り扱いますので、ここでは順編成ファイルを対象にします。
ソートするキー項目が次のように並んでいるファイルAをソートすることを考えます(キー項目以外の項目は煩雑になるので省略します)。
ファイルA
① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨
┌──┬──┬──┬──┬──┬──┬──┬──┬──┐
│30│60│93│14│84│41│71│53│26│
└──┴──┴──┴──┴──┴──┴──┴──┴──┘
アルゴリズム
①~③ や ④~⑤ など、部分的には既にソートされています。ソートされている部分を連といいます。
ファイルAを連ごとに別のファイル(ワークファイルといいます)に出力すれば、
30、60、90
14、84
41、71
53
26
の4つのファイルになります。
この4つのファイルをマージすればソートが完成します。
複数のファイルをマージするソフトウェアがあるにせよ、せいぜい数ファイルを想定しているのであり、ワークファイルの個数が数百、数千のファイルになる場合には使えません。それで、限られたワークファイルでソートする工夫をする必要があります。ここでは、ワークファイルをファイルBとファイルCの2つであるとします。
このファイルAはソートされていません。それでまた分割とマージを行います。これを繰り返すことにより、ソートができます。
ファイルA:14、30、60、84、53、90、41、71、26
ファイルB:14、30、60、84、41、71、
ファイルC:53、90、26
ファイルA:14、30、53、60、84、41、71、90、26
ファイルB:14、30、53、60、84、26
ファイルC:41、71、90、
ファイルA:14、30、41、53、60、71、84、26、90
ファイルB:14、30、41、53、60、71、84
ファイルC:26、90
ファイルA:14、26、30、41、53、60、71、84、90
ソート終了
以上からわかるように、連の個数が多いと、分割とマージの回数が多くなり、入出力回数が増大し、効率が悪くなります。
最も効率が悪いのは、ファイルAが逆順にソートされているときです。