ヒープソート.

Slides:



Advertisements
Similar presentations
区間グラフにおける区間表現からMPQ-treeを効率よく構成するアルゴリズム
Advertisements

4.3 マージソート.
プログラムのパタン演習 解説.
離散システム特論 整列(sorting)アルゴリズム 2.
ヒープソートの演習 第13回.
2 分探索木 Binary Search Tree 実行可能な操作 計算量 木の高さは,最悪 O(n) n = |A| : 要素の個数
アルゴリズムとデータ構造 第8回 ソート(3).
第10回 整列 ~ バブルソート,挿入ソート,選択ソート~
第11回 整列 ~ シェルソート,クイックソート ~
アルゴリズムとデータ構造 2013年6月18日
第11回 整列 ~ バケットソート,基数ソート,ヒープソート~
On the Enumeration of Colored Trees
Problem G : Entangled Tree
アルゴリズムとデータ構造 第6回演習解答 2015/11/18実施 アルゴリズムとデータ構造 2015.
2009/10/9 良いアルゴリズムとは 第2講: 平成21年10月9日 (金) 4限 E252教室 コンピュータアルゴリズム.
第10回 ソート(1):単純なソートアルゴリズム
C言語 配列 2016年 吉田研究室.
アルゴリズムとデータ構造 2012年6月14日
情報工学概論 (アルゴリズムとデータ構造)
情報工学概論 (アルゴリズムとデータ構造)
岩井 儀雄 コンピュータ基礎演習  ー探索、整列ー 岩井 儀雄
エージェントを管理するボスの苦悩 問題 n人のエージェントを部下に持つボスがいる. エージェントは出張・帰還を頻繁に繰り返す.
ヒープソートの復習.
アルゴリズムとデータ構造 2011年6月14日
第11回 整列 ~ シェルソート,クイックソート ~
二分探索木によるサーチ.
第7回 条件による繰り返し.
2009/10/16 いろいろなデータ構造 第3講: 平成21年10月16日 (金) 4限 E252教室 コンピュータアルゴリズム.
算法数理工学 第3回 定兼 邦彦.
決定木とランダムフォレスト 和田 俊和.
情報工学概論 (アルゴリズムとデータ構造)
アルゴリズムとデータ構造1 2005年7月15日
情報工学概論 (アルゴリズムとデータ構造)
第7回 条件による繰り返し.
岩村雅一 知能情報工学演習I 第10回(後半第4回) 岩村雅一
アルゴリズムとデータ構造 第3章 ヒープ 6月10日分
第9回 優先度つき待ち行列,ヒープ,二分探索木
クイックソート.
A Simple Algorithm for Generating Unordered Rooted Trees
基本情報技術概論(第6回) 埼玉大学 理工学研究科 堀山 貴史
Cプログラミング演習 第10回 二分探索木.
アルゴリズムとプログラミング (Algorithms and Programming)
データ構造とアルゴリズム論 第5章 整列(ソート)のアルゴリズム
プログラミング 4 整列アルゴリズム.
2009/10/23 整列アルゴリズム (1) 第4講: 平成21年10月23日 (金) 4限 E252教室 コンピュータアルゴリズム.
プログラミング 4 探索と計算量.
プログラミング 4 木構造とヒープ.
アルゴリズムとデータ構造1 2006年7月11日
15.cons と種々のデータ構造.
アルゴリズムとデータ構造 第3章 ヒープ 5月31日分
情報知能学科「アルゴリズムとデータ構造」
アルゴリズムとデータ構造 第3章 ヒープ 5月31日分の復習
データ構造とアルゴリズム (第5回) 静岡大学工学部 安藤和敏
第9回 優先度つき待ち行列,ヒープ,二分探索木
ハフマン符号長の効率的な求め方.
アルゴリズムとデータ構造 2012年7月2日
アルゴリズムとプログラミング (Algorithms and Programming)
アルゴリズムとデータ構造 2011年6月28日
アルゴリズムとデータ構造 2011年6月16日
基本情報技術概論(第6回) 埼玉大学 理工学研究科 堀山 貴史
ヒープソートの復習 第12回.
情報工学概論 (アルゴリズムとデータ構造)
アルゴリズムとデータ構造 2013年7月2日
ソートのプログラムの流れ 配列の中身を小さい順に並び替える a[1],a[2],…a[n]の値を順に出力する
平面走査法を使った 一般線分の 交点列挙アルゴリズム
ヒープソート.
アルゴリズムとデータ構造 2013年6月20日
参考:大きい要素の処理.
Ibaraki Univ. Dept of Electrical & Electronic Eng.
プログラミング論 バイナリーサーチ 1.
Presentation transcript:

ヒープソート

計算量 アルゴリズムの性能を評価するのに「計算量」という概念を用いる 計算量とは: そのアルゴリズムが,おおよそどれだけのステップ数で実行可能かを表す O(n) などのO記号で表す(読み方は,オーダ n) ある関数 g(n)が O(f(n))であるとは,次のような条件を満たすときに成立 g(n) = O(f(n)) ⇔ (∃c>0)(∃n0≧0)(∀n≧n0) g(n)≦c・f(n)

ヒープソート 計算量 基本的な考え方 O(n log n)の計算量を持つソートアルゴリズム 選択法の改良 n個の値が入った配列 a[n] のソート for ( i = n - 1; i > 0; i--) { a[0],...,a[i]の中で最大値を求め, a[p]とする; a[i]と a[p]を入れ替える; }

ヒープソートの特徴 選択法 ヒープソート 各ステップで,最大値を求める操作を繰り返す 途中で得られる情報を捨てる → 残りのデータの大小関係についての情報を捨てる ヒープソート 途中で得られる情報をデータ構造に蓄える → 残りのデータの大小関係の情報をデータ構造の中に蓄えて,少ない手間で最大値を求める

部分順序付き木 2分木の構造 最大値を根ノードに置く 各ノードの値が,その下の左右2つの子供の値よりも大きくなるようにした木(子供同士どちらが大きいかは問わない) 25 22 20 15 5 19 10 7 18 13 1 図:部分順序付き木の例

部分順序付き木での 最大値の取り出し 常に,木の根にある値が最大値となる 最大値を求めるだけなら,O(1)の計算量 最大値を取り除いた後に,再び部分順序付き木の条件を満たすように木を作り直すことが必要 1. 取り除いた頂点の場所 に左右の子供のうち値の 大きい方を移す. 2. これを木の一番下の段 に達するまで繰り返す 22 22 20 20 10 5 10 5 図:部分順序付き木の組み替え

ヒープソートで用いるデータ構造 部分順序付き木を配列上に表現 具体的なデータ構造の例 配列の先頭 a[0]に木の根を置く それ以外は,頂点 a[i] の左の子供を a[2*i+1] に 右の子供を a[2*i+2] に置く 1 2 3 4 5 6 7 8 9 2 1 親子子 親 子子    親 子子 親 子子 親 子 3 4 5 6 7 8 9 ヒープの各頂点の添字と配列の対応(n = 10 の場合)

ヒープ 2*i+1 や 2*i+2 が配列の要素数を越えている場合は子がないものと見なす 配列を隙間なく使う ある頂点からその親に行くのも,子に行くのも添字の計算だけでできる 配列上に表現した部分順序付き木をヒープと呼ぶ

ヒープの特徴 完全二分木の一部のみを表現できる 一般の「木」を表すことはできない 葉までの深さが k または k+1のいずれかで,しかも深さ k+1の葉がすべて左側によせてあるもののみ表現できる

ヒープでの最大値の取り出し 最初に,a[n - 1] をa[0] に移動 次に,部分順序木の木の条件を満たすように木の作り替えを行う 取り除いた頂点の代わりに子供を持ってくるだけでは,完全2分木の形がくずれる 最初に,配列の最後の要素 a[n - 1] をa[0] に移動して,nを1減らす → これで要素数が1減った完全二分木ができる 次に,部分順序木の木の条件を満たすように木の作り替えを行う a[n - 1] を a[0] に移動したときに,部分順序付き木の条件が満たされていないのは,a[0] とその子供の間だけ → 1点 a[k] とその子供の間でだけ条件がくずれているヒープを正しく作り直すアルゴリズム: downheap アルゴリズム(入力として k=1, r=n を与える)

DownHeapアルゴリズム 入力 計算量 k ヒープの条件がくずれている位置 r 現在のヒープの要素数 - 1 木の高さが O(log n), 交換一回当たりの手間が O(1)なので,全体の計算量は O(log n)

DownHeapアルゴリズム手順 j = 2k + 1とする. j ≦r ならば (a)j≠r ならば a[j] と a[j + 1]を比較して大きい方を j とする. (b) i. もし a[k] が a[j] 以上ならば終了. ii.そうでなければ,a[k]と a[j]の値を入れ替え, その後 k = j, j = 2k +1 として2.へ

左右の子の大きいほうと交換する。このいずれも自分より小さいか、ヒープの底までたどり着いたら終了。 5 左右の子の大きいほうと交換する。このいずれも自分より小さいか、ヒープの底までたどり着いたら終了。 7 8 4 5 7 6 1 2 3 8 8 5 7 7 7 4 5 7 6 4 5 5 6 1 2 3 1 2 3

HeapMainアルゴリズムト DownHeap を用いて,ヒープソートを行うアルゴリズム (a) a[0]とa[i]の値を入れ替える. (b) i = i - 1とする. (c) k = 0, r = i としてDownHeapを呼び出す. (d) 2. へ ヒープから最大値を取り出して,ヒープの大きさを1減らして,DownHeapを用いてヒープを再構築する,という操作を繰り返す

InitializeHeapアルゴリズム(1/3) 与えられたデータからヒープのデータ構造を作るアルゴリズム i = [n/2] -1 とする. i ≧0ならば k = i, r = n-1 として DownHeapを呼び出す i = i - 1とする 2. へ

InitializeHeapアルゴリズム(2/3) 木を下の方から積み上げていってヒープを完成させるという方法 配列の初期状態 a[n/2], a[n/2 + 1], ... ,a[n-1]は,子供を持たない単独の頂点 それぞれ単独では,部分付き順序木の条件を満足

InitializeHeapアルゴリズム(3/3) 初期状態を出発点として,全体として1つの木を作る 木を2つずつ組み合わせる操作を続けて,全体として1つの木にを作る(ヒープが完成) 2. で a[i]を根とする部分木をヒープの条件を満たすように作り替える この時,a[2*i + 1]とa[2*i + 2]をそれぞれ根とする木はすでに部分ヒープになっている i 2 1 2*i+1 2*i+2 図:ヒープの初期化操作 3 4 5 6 7 8 9

ヒープソートの実現 ソートすべきデータの,配列への取り込み InitializeHeapにより,ヒープを構成 構成したヒープに,HeapMainを適用

ヒープを作る操作の計算量 DownHeapで調べる段数: iが [n/2]~n の範囲では0段 [n/4] ~ [n/4]の範囲では1段 全体では k = [log n]とするとこの式は次の式の値を越えない k =O(log n)なので,この式のオーダはO(n) 0* +1* +2* +・・・+(log n-1)*1 2 n 4 8 1*2k-2+2*2k-3+・・・+(k-2)*2+(k-1)*1 = 2k-(k+1)

ヒープソートの計算量 ヒープを作る操作(InitializeHeap)の計算量 最大値を取り出す操作(HeapMain)の計算量 O(nlog n) 最大値を取り出す操作(HeapMain)の計算量 ヒープソート全体の計算量 これらの和: O(nlog n)

サンプルプログラム /*  0 1     2 3 4    5 6         7 8 9 10 11 12 13 14 */ #include<stdio.h> FILE *infile, *outfile; int tree[10000]; main() { int i, n, in[20], out[20]; printf("Input InFilename :"); /*入力データのファイル名を入力*/ scanf("%s", in); if ((infile=fopen(in, "r")) == NULL) { printf("can't open file %s\n", in); exit(); } printf("Input OutFilename :"); /*出力データのファイル名を入力*/ scanf("%s", out); if ((outfile=fopen(out,"w")) == NULL) { printf("can't open file %s\n", out);

n=0; while(fscanf(infile,"%d", &(tree[n])) != EOF) { n++; } InitializeHeap(n); HeapMain(n); for (i=0; i<n; i++) { fprintf(outfile,"%d\n", tree[i]); fclose(outfile); fclose(infile); HeapMain(int n) { /*ヒープソートを行う*/ int i, k, r, tmp; i=n-1; while (i>=0) { tmp = tree[0]; tree[0] = tree[i]; tree[i] = tmp; i--; k = 0; r = i; DownHeap(k, r);

InitializeHeap(int n) { /*ヒープを構成する*/ int i, k, r; for (i = n/2-1; i >= 0; i--){ k=i; r=n-1; DownHeap(k,r); } DownHeap(int k, int r) { /*ヒープを正しく作り直す*/ int j, tmp; j = 2*k+1; while (j <= r){ if ((j!=r) & (tree[j+1]>tree[j]))j=j+1; if (tree[k] >= tree[j]) { break; else{ tmp=tree[k]; tree[k]=tree[j]; tree[j]=tmp; tmp=k; k=j; j=2*tmp+1;