アルゴリズムのお勉強
兼 前期中間対策
マージソート分
※注意書き
• 確実にテスト対策になる確証はありません
• あくまでお勉強用です
• 過去の経験やノートを参考にしています
• あと変なノリが含まれます
• あと、責任は取りません…というか取れません
それでもいいなら進めていってください。
マージソート
• ソートアルゴリズムの一種
• 分割統治法 ということで…マージソートも
テスト範囲だったので追加説明です。
マージソート
• ソートアルゴリズムの一種
• 分割統治法 マージソートもクイックソート同様に
分割統治法の一種です。
マージソート
• ソートアルゴリズムの一種
• 分割統治法 クイックソートは要素を
小さいものと大きいものに分けてましたが
マージソート
• ソートアルゴリズムの一種
• 分割統治法 マージソートは単純に半分に分けます。
そのあと連結させるときに秘密があります。
マージソート
入力 : 整数列A(A1, A2, …, An)
出力 : 入力列を昇順に整列した列B
• 0 データが1つならば終了する;
• 1 列のn/2番目までをP1, それ以降をP2とする;
• 2 P1とP2をそれぞれ独立に整列する;
• 3 for i ← 1 to n do
• 4 | if head(P1) < head(P2)
• 5 | | Bi ← head(P1);
• 6 | | head(P1)をP1から除去する;
• 7 | end
• 8 | else
• 9 | | Bi ← head(P2);
• 10 | | head(P2)をP2から除去する;
• 11 | end
• 12 end
• 13 BiのすべてをAiに入れる
それでは早速。
こちらがマージソートの疑似言語です。
マージソート
入力 : 整数列A(A1, A2, …, An)
出力 : 入力列を昇順に整列した列B
• 0 データが1つならば終了する;
• 1 列のn/2番目までをP1, それ以降をP2とする;
• 2 P1とP2をそれぞれ独立に整列する;
• 3 for i ← 1 to n do
• 4 | if head(P1) < head(P2)
• 5 | | Bi ← head(P1);
• 6 | | head(P1)をP1から除去する;
• 7 | end
• 8 | else
• 9 | | Bi ← head(P2);
• 10 | | head(P2)をP2から除去する;
• 11 | end
• 12 end
• 13 BiのすべてをAiに入れる
入力、出力ともに配列ですね。
マージソート
入力 : 整数列A(A1, A2, …, An)
出力 : 入力列を昇順に整列した列B
• 0 データが1つならば終了する;
• 1 列のn/2番目までをP1, それ以降をP2とする;
• 2 P1とP2をそれぞれ独立に整列する;
• 3 for i ← 1 to n do
• 4 | if head(P1) < head(P2)
• 5 | | Bi ← head(P1);
• 6 | | head(P1)をP1から除去する;
• 7 | end
• 8 | else
• 9 | | Bi ← head(P2);
• 10 | | head(P2)をP2から除去する;
• 11 | end
• 12 end
• 13 BiのすべてをAiに入れる
マージソートも分割統治法なので、
ここが再帰的に呼び出しを行う部分です。
マージソート
入力 : 整数列A(A1, A2, …, An)
出力 : 入力列を昇順に整列した列B
• 0 データが1つならば終了する;
• 1 列のn/2番目までをP1, それ以降をP2とする;
• 2 P1とP2をそれぞれ独立に整列する;
• 3 for i ← 1 to n do
• 4 | if head(P1) < head(P2)
• 5 | | Bi ← head(P1);
• 6 | | head(P1)をP1から除去する;
• 7 | end
• 8 | else
• 9 | | Bi ← head(P2);
• 10 | | head(P2)をP2から除去する;
• 11 | end
• 12 end
• 13 BiのすべてをAiに入れる
その終了条件はこちらになりますね。
マージソート
入力 : 整数列A(A1, A2, …, An)
出力 : 入力列を昇順に整列した列B
• 0 データが1つならば終了する;
• 1 列のn/2番目までをP1, それ以降をP2とする;
• 2 P1とP2をそれぞれ独立に整列する;
• 3 for i ← 1 to n do
• 4 | if head(P1) < head(P2)
• 5 | | Bi ← head(P1);
• 6 | | head(P1)をP1から除去する;
• 7 | end
• 8 | else
• 9 | | Bi ← head(P2);
• 10 | | head(P2)をP2から除去する;
• 11 | end
• 12 end
• 13 BiのすべてをAiに入れる
P1とP2は配列の前か、後ろかだけなので、
P2の中にP1の要素より小さい要素が
存在する可能性があります。
マージソート
入力 : 整数列A(A1, A2, …, An)
出力 : 入力列を昇順に整列した列B
• 0 データが1つならば終了する;
• 1 列のn/2番目までをP1, それ以降をP2とする;
• 2 P1とP2をそれぞれ独立に整列する;
• 3 for i ← 1 to n do
• 4 | if head(P1) < head(P2)
• 5 | | Bi ← head(P1);
• 6 | | head(P1)をP1から除去する;
• 7 | end
• 8 | else
• 9 | | Bi ← head(P2);
• 10 | | head(P2)をP2から除去する;
• 11 | end
• 12 end
• 13 BiのすべてをAiに入れる
その比較を行っているのがこちらになります。
マージソート
入力 : 整数列A(A1, A2, …, An)
出力 : 入力列を昇順に整列した列B
• 0 データが1つならば終了する;
• 1 列のn/2番目までをP1, それ以降をP2とする;
• 2 P1とP2をそれぞれ独立に整列する;
• 3 for i ← 1 to n do
• 4 | if head(P1) < head(P2)
• 5 | | Bi ← head(P1);
• 6 | | head(P1)をP1から除去する;
• 7 | end
• 8 | else
• 9 | | Bi ← head(P2);
• 10 | | head(P2)をP2から除去する;
• 11 | end
• 12 end
• 13 BiのすべてをAiに入れる
まず、前提としてこの行により
P1の中身、P2の中身は
それぞれで整列されています。
マージソート
入力 : 整数列A(A1, A2, …, An)
出力 : 入力列を昇順に整列した列B
• 0 データが1つならば終了する;
• 1 列のn/2番目までをP1, それ以降をP2とする;
• 2 P1とP2をそれぞれ独立に整列する;
• 3 for i ← 1 to n do
• 4 | if head(P1) < head(P2)
• 5 | | Bi ← head(P1);
• 6 | | head(P1)をP1から除去する;
• 7 | end
• 8 | else
• 9 | | Bi ← head(P2);
• 10 | | head(P2)をP2から除去する;
• 11 | end
• 12 end
• 13 BiのすべてをAiに入れる
繰り返し回数は全体の要素の数ですね。
マージソート
入力 : 整数列A(A1, A2, …, An)
出力 : 入力列を昇順に整列した列B
• 0 データが1つならば終了する;
• 1 列のn/2番目までをP1, それ以降をP2とする;
• 2 P1とP2をそれぞれ独立に整列する;
• 3 for i ← 1 to n do
• 4 | if head(P1) < head(P2)
• 5 | | Bi ← head(P1);
• 6 | | head(P1)をP1から除去する;
• 7 | end
• 8 | else
• 9 | | Bi ← head(P2);
• 10 | | head(P2)をP2から除去する;
• 11 | end
• 12 end
• 13 BiのすべてをAiに入れる
このheadというのはそれぞれの配列の先頭
の要素を返す関数です。
つまり配列の最小値を返します。
マージソート
入力 : 整数列A(A1, A2, …, An)
出力 : 入力列を昇順に整列した列B
• 0 データが1つならば終了する;
• 1 列のn/2番目までをP1, それ以降をP2とする;
• 2 P1とP2をそれぞれ独立に整列する;
• 3 for i ← 1 to n do
• 4 | if head(P1) < head(P2)
• 5 | | Bi ← head(P1);
• 6 | | head(P1)をP1から除去する;
• 7 | end
• 8 | else
• 9 | | Bi ← head(P2);
• 10 | | head(P2)をP2から除去する;
• 11 | end
• 12 end
• 13 BiのすべてをAiに入れる
つまり一番小さいもの同士を
比較することになりますね。
マージソート
入力 : 整数列A(A1, A2, …, An)
出力 : 入力列を昇順に整列した列B
• 0 データが1つならば終了する;
• 1 列のn/2番目までをP1, それ以降をP2とする;
• 2 P1とP2をそれぞれ独立に整列する;
• 3 for i ← 1 to n do
• 4 | if head(P1) < head(P2)
• 5 | | Bi ← head(P1);
• 6 | | head(P1)をP1から除去する;
• 7 | end
• 8 | else
• 9 | | Bi ← head(P2);
• 10 | | head(P2)をP2から除去する;
• 11 | end
• 12 end
• 13 BiのすべてをAiに入れる
といことは、すべての要素で
一番小さい要素を求めることができます。
マージソート
入力 : 整数列A(A1, A2, …, An)
出力 : 入力列を昇順に整列した列B
• 0 データが1つならば終了する;
• 1 列のn/2番目までをP1, それ以降をP2とする;
• 2 P1とP2をそれぞれ独立に整列する;
• 3 for i ← 1 to n do
• 4 | if head(P1) < head(P2)
• 5 | | Bi ← head(P1);
• 6 | | head(P1)をP1から除去する;
• 7 | end
• 8 | else
• 9 | | Bi ← head(P2);
• 10 | | head(P2)をP2から除去する;
• 11 | end
• 12 end
• 13 BiのすべてをAiに入れる
小さかった方を、答えの配列に追加して…
マージソート
入力 : 整数列A(A1, A2, …, An)
出力 : 入力列を昇順に整列した列B
• 0 データが1つならば終了する;
• 1 列のn/2番目までをP1, それ以降をP2とする;
• 2 P1とP2をそれぞれ独立に整列する;
• 3 for i ← 1 to n do
• 4 | if head(P1) < head(P2)
• 5 | | Bi ← head(P1);
• 6 | | head(P1)をP1から除去する;
• 7 | end
• 8 | else
• 9 | | Bi ← head(P2);
• 10 | | head(P2)をP2から除去する;
• 11 | end
• 12 end
• 13 BiのすべてをAiに入れる
その要素は除去、
つまり吐き出したことになります。
マージソート
入力 : 整数列A(A1, A2, …, An)
出力 : 入力列を昇順に整列した列B
• 0 データが1つならば終了する;
• 1 列のn/2番目までをP1, それ以降をP2とする;
• 2 P1とP2をそれぞれ独立に整列する;
• 3 for i ← 1 to n do
• 4 | if head(P1) < head(P2)
• 5 | | Bi ← head(P1);
• 6 | | head(P1)をP1から除去する;
• 7 | end
• 8 | else
• 9 | | Bi ← head(P2);
• 10 | | head(P2)をP2から除去する;
• 11 | end
• 12 end
• 13 BiのすべてをAiに入れる
次の比較では、先ほどの一番小さい要素を
除いて行われます。
つまり2番目に小さい要素を求めます。
マージソート
入力 : 整数列A(A1, A2, …, An)
出力 : 入力列を昇順に整列した列B
• 0 データが1つならば終了する;
• 1 列のn/2番目までをP1, それ以降をP2とする;
• 2 P1とP2をそれぞれ独立に整列する;
• 3 for i ← 1 to n do
• 4 | if head(P1) < head(P2)
• 5 | | Bi ← head(P1);
• 6 | | head(P1)をP1から除去する;
• 7 | end
• 8 | else
• 9 | | Bi ← head(P2);
• 10 | | head(P2)をP2から除去する;
• 11 | end
• 12 end
• 13 BiのすべてをAiに入れる
あとはこれを繰り返していけば…
最終的にすべての要素を
並べることができますね。
マージソート
入力 : 整数列A(A1, A2, …, An)
出力 : 入力列を昇順に整列した列B
• 0 データが1つならば終了する;
• 1 列のn/2番目までをP1, それ以降をP2とする;
• 2 P1とP2をそれぞれ独立に整列する;
• 3 for i ← 1 to n do
• 4 | if head(P1) < head(P2)
• 5 | | Bi ← head(P1);
• 6 | | head(P1)をP1から除去する;
• 7 | end
• 8 | else
• 9 | | Bi ← head(P2);
• 10 | | head(P2)をP2から除去する;
• 11 | end
• 12 end
• 13 BiのすべてをAiに入れる
最後に、出力列を入力列に戻します。
マージソート
head関数について説明します。
head関数は配列要素の
先頭の値を返します。
マージソート
ここで、要素が空だった場合は∞を返します。
これにより同じ処理で、比較できるわけです。
マージソート
それでは、
マージソートの動作を確認してみましょう。
5134 2
マージソート
ノートの方は2分割の都合上
要素数が8ですが…
要素数5でやってみましょう。
5134 2
マージソート
疑似言語より、要素数が5なので
5/2=2
添字<2をP1としましょう。
5134 2
列のn/2番目までをP1, それ以降をP2とする;
マージソート
8だった場合は
8/2=4
添字<4でちょうど半分ですね。
5134 2
列のn/2番目までをP1, それ以降をP2とする;
マージソート
まず、添え字が2未満をP1
それ以降をP2とします。
5134 2
134 5 2
マージソート
左側では要素数2より2/2=1、
添字<1をP1、
それ以降をP2としますね。
5134 2
134 5 2
4 3
マージソート
右側は要素数3より3/2=1、
添字<1をP1、
それ以降をP2とします。
5134 2
134 5 2
1 5 24 3
マージソート
右側はさらに分割できるのでこうなりますね。
5134 2
134 5 2
1 5 24 3
5 2
マージソート
まず5と2から計算していきましょう。
5134 2
134 5 2
1 5 24 3
5 2
マージソート
5<2で2を追加します。
5 2
マージソート
こうなりますね。
ここで2を除去します。
2
5 2
マージソート
P2は空集合なのでheadは∞になります。
つまり5<∞の比較で5が入ります。
2
5
マージソート
これで、一回分の併合(マージ)が
完了しました。
2 5
マージソート
どんどん行きましょう。
1と2の比較ですね。
1 2 5
マージソート
左は空なので∞となります。
2が入って…1
2 5
マージソート
5も∞と比較されて…
1 2
5
マージソート
こうなりました。
1 2 5
マージソート
同様に4と3も併合されます。
143 2 5
マージソート
では、最後もやってみましょう。
143 2 5
マージソート
3と1で1ですね。
143 2 5
マージソート
3と2で2ですね。
1
43 2 5
マージソート
3と5で3ですね。
21
43 5
マージソート
4と5で4ですね。
321
4 5
マージソート
最後は5ですね。
4321
5
マージソート
できました。
これがマージソートです。
4321 5
以上
以上簡単ですが、
マージソートとなります。
教科書
• アルゴリズムとデータ構造 数理工学社 藤田 聡 2013/3/10
教科書のため、ところどころ引用になってる場所があります
立ち絵素材
• 臼井の会様 http://usui.moo.jp/frame2.html
ご視聴ありがとうございました。
頑張ってくださいね。

アルゴリズムのお勉強 マージソート 試験対策