ヒープソート c 言語。 C言語講座:ヒープソート

クイックソートのアルゴリズムをわかりやすく解説します!

ヒープソート c 言語

マージソート マージソートとは マージ merge とは、「合わせる」、「融合する」といういみの英語です。 このソートは、並べ替えるデータを一度ばらばらにして、それを再びマージする過程で並べ替えると、最終的に一つのデータに戻るときには、自然に並べ替えられているというアルゴリズムです。 マージソートの構造 では、実際にもう少し詳しくマージソートによって数値を降順に並べ替える過程を解説していきましょう。 並べ替えるデータを、二つに分割し、さらに文化史されたものも再分割します。 データが完全にばらばらになるまで分割を続けます。 分割がおわったら、マージを開始します。 並べる際には、先頭から大きなデータを入れていきます。 最終的に、すべてのデータのマージが終わると、並べ替えが終了しています。 以上が、マージソートのアルゴリズムです。 図7-1. 参照 図7-1. マージソートの構造 マージソートの実装 以下、各言語でのマージソートの実装を紹介します。 ヒープソート ヒープソートとは ヒープソートとは、ヒープ構造に説明したものです。 ヒープ構造とは、特殊な二分木です。 ヒープとは、親ノードが、子ノードよりも必ず大きい、または小さいという構造を持つデータ構造です。 この仕組みを利用し、ルートノードに最大値(もしくは最小値)が来るようにし、その値を順次取り出すことによってソートを行うのがこのソートの構造です。 アルゴリズムの手順 では、整数値を降順に並べ替えるケースを例にして、実際のアルゴリズムを見てみましょう。 並べ替えるデータを二分木に配置します。 ルートノードを皮切りに、以後、子ノードに分配していきます。 配置したのとは逆方向から、子ノードの値が親ノードより大きければ、入れ替えます。 すべての探索が終わると、ルートに最大値が残るので、それを取り出し、末端の値をルートに入れます。 以後、同じ処理を繰り返します• すべての処理が終了すると、並べ替え処理がおわります。 図7-2. ヒープソートの構造 ヒープソートの実装 以下、各言語でのヒープソートの実装を紹介します。 クイックソート クイックソートとは バブルソートは、アルゴリズムが単純ですが、探索に時間がかかるという問題点がありました。 そのためある程度大量のデータをソートするならば、もう少し早いソートアルゴリズムが必要です。 そこで、ここではまず、そういったアルゴリズムの一つである、 クイックソートについて解説します。 その名の通り、速い(quick)なソートですが、手順が少々複雑です。 では、実際にその手順を見てみましょう。 アルゴリズムの手順 クイックソートにおいて、一番最初にやらなければならない処理は、まず、 軸要素(じくようそ)と呼ばれる値の決定です。 その方法には、さまざまな方法がありますが、ここでは一番単純に、データの先頭にある要素を軸要素とします。 図5-2. 参照 では実際に、昇順でのソートの手順を見てみましょう。 アルゴリズムは、以下のようになります。 軸要素を決定する。 先頭から末端に向かって、軸要素以上の値の探索、逆方向から軸要素の値未満の探索し、見つかったら値同士を交換する。 先頭からの探索と、末端からの探索がぶつかった時点で、探索を終了し、交差した時点で、データを二つに分ける。 分割したそれぞれの要素で、同様の処理を繰り返し、最終的に、交換する部分がなくなった時点で処理を終了する。 図7-3. クイックソートの構造.

次の

C言語 アルゴリズムを覚える クイックソートを覚えるぞ、基本情報技術者試験、午後問題対策ピクチャ

ヒープソート c 言語

[ ] ソート 2 の続きです。 今回はヒープソートとマージソートという高速なソートアルゴリズムを説明します。 それから、連結リストのソートについて説明します。 実は、このヒープを使ったソートも優秀なアルゴリズムの一つです。 しかし、クイックソートとは違って、データの種類によって性能が劣化することはありません。 プログラムは次のようになります。 親子関係が の説明と逆になっていることに注意してください。 つまり、親が子より大きいという関係を満たすようにヒープを構築します。 したがって、配列の先頭 buff[0] が最大値になります。 後半部分で、最大値を取り出してヒープを再構築します。 配列の先頭には最大値がセットされているので、これを配列の最後尾のデータと交換します。 あとは、そのデータを除いた範囲でヒープを再構築すれば、その次に大きいデータを求めることができます。 これを繰り返すことで、大きいデータが配列の後ろから整列していくことになります。 最初の for ループで、配列の前半部分のデータを後ろから順番に取り出します。 次の while ループで、親子関係を満たすように修正します。 変数 n が親の位置を、変数 c が子の位置を示します。 次に、後半の for ループで、最大値 buff[0] と最後尾のデータ buff[i] を交換します。 そして、while ループでヒープの再構築を行います。 あとはヒープのプログラムとほとんど同じですが、ヒープを再構築する範囲が変数 i で管理されていて、その値は一つずつ減っていくことに注意してください。 表 : heap sort の結果 単位 : 秒 個数 乱数 昇順 逆順 山型 ------------------------------------- 1000000 : 0. 198 0. 091 0. 101 0. 118 2000000 : 0. 507 0. 197 0. 217 0. 256 4000000 : 1. 267 0. 428 0. 469 0. 555 8000000 : 3. 038 0. 923 0. 985 1. 191 実行環境 : Lubuntu 14. 10 on VirtualBox, Core i7-2670QM 2. 20GHz このように、ヒープソートはどのデータに対しても、そこそこの速度でソートすることができます。 ただし、実行時間はクイックソートだけではなくシェルソートやコムソートよりも遅くなってしまいました。 ヒープソートの処理内容は他のソートアルゴリズムよりも複雑なので、時間がかかるのは仕方がないのかもしれません。 また、M. Hiroi のコーディングに何か問題があるのかもしれません。 お気づきの点がありましたら、ご教示お願いいたします。 このマージを使ったソートを「マージソート merge sort 」といいます。 最初にマージについて簡単に説明します。 次の図を見てください。 図 : マージの考え方 2 つのリスト a と b があります。 これらのリストはソート済みとしましょう。 これらのリストをソート済みのリストにまとめることを考えます。 a と b はソート済みなので先頭のデータがいちばん小さな値です。 したがって、上図のように先頭のデータを比較し、小さい方のデータを取り出して順番に並べていけば、ソート済みのリストにまとめることができます。 途中でどちらかのリストが空になったら、残ったリストのデータをそのまま追加します。 次の図を見てください。 9 5 3 7 6 4 2 8 最初の状態 5 9 3 7 4 6 2 8 長さ2の列に併合 3 5 7 9 2 4 6 8 長さ4の列に併合 2 3 4 5 6 7 8 9 ソート終了 図 : マージソート マージをソートに応用する場合、最初は各要素をソート済みの配列として考えます。 この状態で隣の配列とマージを行い、長さ 2 の配列を作ります。 次に、この配列に対して再度マージを行い、長さ 4 の配列を作ります。 このように順番にマージしていくと、最後には一つの配列にマージされソートが完了します。 配列の長さを 1, 2, 4, 8,... と増やしていくよりも、再帰的に考えた方が簡単です。 マージは 2 つの列を一つの列にまとめる操作です。 そこで、まずソートする配列を 2 つに分けて、前半部分をソートします。 次に後半部分をソートして、その結果をマージすればいいわけです。 では、どうやってソートするのかというと、再帰呼び出しするのです。 そうすると、どんどん配列を 2 つに割っていくことになり、最後にデータが一つとなります。 それはソート済みの配列と考えることができるので、再帰呼び出しを終了してマージ処理に移ることができます。 あとはデータを順番にマージしていってソートが完了します。 プログラムは次のようになります。 メンバ変数 next が次のセルへのポインタです。 クイックソートのプログラムは次のようになります。 これが再帰呼び出しの停止条件になります。 リストの分割は関数 partition で行います。 枢軸未満のデータはリスト small に、枢軸以上のデータはリスト big に格納します。 それから、枢軸の後ろに big を接続して、関数 nconc で small と top を連結します。 ループの最後で、xs を ys に更新します。 これで、次のセルに進むことができます。 関数 nconc は引数 xs と ys を連結します。 xs が NULL の場合は ys をそのまま返します。 次に、xs を変数 cp にセットして、while ループで末尾のセルを求めます。 さっそく実行してみましょう。 この関数は連結リストを破壊的に修正してマージします。 最初に連結リストのヘッダ head を用意します。 このあとに、連結リストをつないでいきます。 変数 cp は最後尾のセルを示します。 マージ処理はとても簡単です。 そして、cp の値をつなげたセルに更新して、次のセルへ進めます。 while ループが終了して、xs に連結リストが残っていれば、それを cp の後ろにつなげます。 xs が空リストであれば ys に残っている連結リストをつなげます。 最後に、return でマージしたリスト head. next を返します。 cp がソートする連結リスト、n が連結リストの長さを表します。 次の図を見てください。 これが再帰の停止条件で、要素数が一つの連結リスト、つまりソート済みの連結リストを返すことになります。 368 2000000 : 0. 875 4000000 : 2. 023 8000000 : 4. 709 クイックソートよりもマージソートのほうが速くなりました。 連結リストのソートはクイックソートよりもマージソートのほうが適していることがわかります。 なお、これらの結果は M. Hiroi のコーディング、実行したマシン、プログラミング言語などの環境に大きく依存しています。 また、これらの環境だけではなく、データの種類によっても実行時間はかなり左右されます。 興味のある方は、いろいろなデータをご自分の環境で試してみてください。

次の

お気楽C言語プログラミング超入門

ヒープソート c 言語

ヒープとは• 半順序集合をツリーで表現したデータ構造• 「親ノードは子ノードよりも小さい(もしくは大きい)か等しい」という条件を満たすツリー構造• 根を配列の最後尾と入れ替える。 次の手順を、根ノードから開始 1. 大きいほうの子と比較 2. 親が大きければヒープ構築済み 3. 親が小さければ子と入れ替えて、さらに下の子と比較 自分より大きな子と入れ替えて、自身を下に下げながらヒープを構築する位置までおろしていく:pushdown操作 配列全体のヒープ化 ヒープソートを行うには、配列がヒープ構造になっていることが前提• 下から、ボトムアップ的にヒープ化する• pushdown操作を使ってヒープ化できる•

次の