#pragma twice

KAB-studio > プログラミング > #pragma twice > 254 Version 13.18 一番便利・マージソート

#pragma twice 254 Version 13.18 一番便利・マージソート

前のページへ 表紙・目次へ 次のページへ

 Version 13.18
一番便利・マージソート

今回は、最後のソート、マージソートについて説明します
最後?
ソートのアルゴリズムは他にもいっぱいあるんだけど、基本的にはクイッ
クソートとマージソートが使えれば問題ないから
クイックソートとマージソート……あ、マージソートは安定ソートなん
だ!
そういうこと。 int とかの配列のソートはクイックソートで、構造体や
クラスの配列のソートはマージソートで、っていうのが基本かな
でも、マージソートってクイックソートより遅いんでしょ?
そんなに遅くないし、場合によってはクイックソートよりも速いよ
え、そうなの?
クイックソートは左右を入れ替えていくソートだから、元々ある程度きれ
いに並んでいる配列をソートするには向かないんだけど、マージソートはむ
しろ並んでいる方が速くソートできるから
そういう場合にはマージソートの方が速いわけね
そういうこと。だから、場合によっては全部マージソートでもいいかも

でもクイックソートはランタイムにあるから便利……
確かに……さて、それではマージソートの仕組みについて説明します。
マージソートは、次のような手順でソートします

1.全部バラバラにする。
2.隣同士をくっつける。そのとき小さい順にくっつける。
3. 2 を繰り返して、全部ひとつになるまで続ける。

……これだけ?
そう。仕組み的にはクイックソートより簡単だと思うよ。ちなみに、この
処理の中の〈くっつける〉ことを merge って言います
だからマージソート、ね
そういうこと。じゃ、実際に手順を追ってみようか

4 9 3 5 8 

前のと同じのね
これをソートします。まず、全部バラバラにします

4     9     3     5     8 

次に、隣同士をマージします
マージする、つまりくっつけるのね
その際、小さい方は左側にします

(4,9) 3 (5,8)

む、なんかそのままね
たまたま左右そう並んでるからね。
あと真ん中の 3 があぶれちゃったけど
これは次にマージするから、今は放っておきます。では、その次の段階

(3,4,9) (5,8)

 (4,9) と 3 をマージしました。 (5,8)は隣がないので放っておきます
 3 が一番左に来てるね
小さい方を左に持ってくるからね。では最後に、このふたつをマージしま


(3,4,5,8,9)

はい、ソートできました
……
う、何怖い顔で
……簡単すぎ! なんかだましてるでしょ!
騙してるわけじゃなくて……タネというか、ポイントは、くっつけると
ころ、つまりマージ。たとえば

(3,4,9)
(5,8)

このふたつをくっつける場合
そうよ、これ、くっつけるって言ったけど、大変じゃないの? 小さい順
なんだから
ところがそうでもないんです。なぜかというと

(3,4,9)



(5,8)

も、すでに小さい順にソート済みだから
小さい順に並んでいると……簡単?
簡単なんです。この手順も追ってみようか

(3,4,9)
(5,8)
 ↓
[,,,,]

という形でマージしていきます。まず1回目。この中から一番小さい数
は?
 3 。あ……そっか、もうこのふたつ、ソートされてるから、一番小さな
数が絶対に一番左に来てるんだ……
そういうこと。それがポイントなんです。一番小さな数は、 3 と 5 を比
較して、 3 

(4,9)
(5,8)
 ↓
[3,,,,]

次に小さな数は、 4 と 5 を比較して 4 

(9)
(5,8)
 ↓
[3,4,,,]

と、常に一番左にある〈一番小さな数〉のふたつを比較するだけでいいん
です
ソートの時は全部見ていかなきゃいけなかったけど、ソート済みだとそれ
が必要ない、ってわけね
残りも同じように見ていきます。 9 と 5 だと 5 だから

(9)
(8)
 ↓
[3,4,5,,]

 9 と 8 だと 8 だから

(9)
()
 ↓
[3,4,5,8,]

そして残った 9 

()
()
 ↓
[3,4,5,8,9]

マージが終わったら、もうそのときソートもされてるわけね……
マージソートの早い理由はこれ。常にソート済みにしておくことで、全体
を見る、という処理をしないで済むわけです
これは早そう……
それに、このソートは左右をそのまま残しておくから
安定ソート!
ってわけ
元々の位置はそのままだものね
そう、それも重要

ごちゃごちゃにかき混ぜるクイックソートに比べて、マージソートはその
ままの並び順をうまく活用するから、〈元々ある程度ソートされてる〉場合
にかなり早くソートできるんです
マージがそのままできるもんね
こういったメリットがあるから、クイックソートは必要ないかも
マージソートのデメリットは?
メモリを多く使うこと。今まで紹介したソートは元々の配列を利用してい
たけど、今回はそうできないんです
どして?
マージの時に別の領域が必要になるから

(3,4,9)
(5,8)
 ↓
[,,,,]

あ”
まぁプログラム的には上の () の領域を作ることになるんだけど
分割した方ってこと?
そう。分割した値を動的に作った配列に入れておいて、マージするときに
元の配列に戻していく、っていう形になります
動的に作る、ってことは、 malloc() とか new とか使うってこと? め
んどくさそう……
確かにそうかも。でもこれも、一度作っちゃえば使い回しできるから、そ
れほど大変じゃないと思うよ
……なんか、マージソートができればもう他には必要ないように聞こえる
けど
実際そうだと思うよ。マージソートの関数をちゃんと作っておけば、もう
それだけで十分かも

/*
    Preview Next Story!
*/
仕組みがわかったらコーディング、ね
というわけで次回はマージソートのコードを紹介します
……あらかじめ訊くけど
ランタイムはないよ
うー
というわけで次回
< Version 13.19 マージソートのコーディング >
につづく!
まぁ他の言語だとあらかじめ用意されてたりするんだけどね
え!? じゃあそっちに乗り換えるー!!
じゃあ #pragma twice が最終回になったらね
え”……
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。