ヒープソート (Heap Sort)

これまで2つのソートは,実際にはソートのためのアルゴリズムとして は,ほとんど使われない. その理由は,時間計算量が,O(n2)と非常に遅かったから である. 以下では,より高速なアルゴリズムをいくつか学ぶ.

バブルソートのような方法では総当たり的に比較を行なっていた. やみくもに最小値を探すことを繰り返し, その過程の比較演算で得られた情報は すべて捨てていた. 時間効率のよいアルゴリズムは,この情報を何らかの方法で ある程度残すことによって,効率を稼いでいる.

ヒープソートではデータ構造として木構造を用いる. 木構造は組織の構成やものの分類などを表現するのに広く用いられる. 1冊の本も,章がいくつかあって,各章の中にはいくつかの節があり, その中にまた小節がある,というように木構造をしている. 木構造は,日々目にする通り,節目(ノード)と枝(アーク)からなる. 節目のうち他の枝の先につかないものがひとつあって,これを根といい, その先に枝の出ない節目を葉という. ヒープソートで用いる木構造は,二分木 (binary tree), すなわち葉でないノードからは1本または2本のアークしか出ないものである. ヒープソートのアルゴリズムは,まず与えられたデータ列を次のような性質をもつ 二分木--ヒープに構成する(図1参照).

  1. 各ノード(根を含む)には,データが1つだけ書いてある.
  2. 葉を除く各ノードにおいて, 自分のデータは,その子のデータより,大きくない.
ひとたび,ヒープが構成できれば,その根には必ず最小のデータが あるので,これを取り除く.次に,根を取り除くことによって壊れた ヒープを再構築する.この手順を繰り返せばソートができる.

図1.ヒープの例

ヒープを配列で実現する場合は, 各レベル(根をレベル0とし,レベルnの子ノードをレベルn+1 とする)のノードを左から右に順番に並べた配列とするのがよい. 図1の例では,1, 2, 5, 6, 3, 7, 10, 9, 8, 4 という順番に 並ぶ.


KADAI

課題6(オプショナル)

注意!この課題はオプショナルである(必修ではない). 余力のある人,あるいは,興味がある人がトライすること.

課題3のソーティングモジュールをヒープソートによるものに差し替えて動かせ. なお,ヒープを作る関数を,再帰的,非再帰的の両方で書いてみよ.

発展課題として,ヒープソートの時間計算量を考えよ.

この課題を解いた場合の提出方法は以下の通り.

  1. Subject: ex1 6th
  2. To: ex1kadai-2012@ai.soc.i.kyoto-u.ac.jp
  3. Cc: 自分のユーザ名
  4. フォーマット
  5. 2012 年度の締切は 7/18 (水) とする.

再帰に関する補足

ヒープは,木である.木は本質的に再帰的な構造であり,以下で定義される. したがって,これを処理するプログラム構造も再帰構造(自分自身を呼び出す 制御構造)が自然である.

再帰的関数(モジュール)の例として,階乗を計算する関数(入力が 自然数であることを仮定)をあげておく.

        int	factorial(int n)
        {
                if (n == 0)
                        return(1);
                else
                        return(n * factorial(n-1));
        }
この関数はもちろん再帰を使わないでも以下のように書ける.
        int     factorial(int n)
        {
                int     pi;

                for (pi=1; n>1; n--)
                        pi *= n;
                return(pi);
        }
再帰的関数の方が,アルゴリズムを自然に,かつ,簡明に表現することが 多い.一方,上記の例では,非再帰的な後者の方が, 実行時の効率がよい.そこで,両方の書き方について学ぶ必要がある.
へ進む.