ヒープソート ~Delphiソースコード集
ヒープソートは完全2分木の構造を活かしたソートアルゴリズムで並び替えを行います。
配列の添え字が0から始まっている場合、ヒープ構造は以下のようになります。
ノードには左の子ノードと右の子ノードの2つがありますが、
最下層のノードには子ノードが無く、
最下層の1つ前の層は子ノードが2個、又は1個、又は0個となります。
a[0] 最上層 / \ / \ / \ a[1] a[2] 2層目 / \ / \ / \ / \ a[3] a[4] a[5] a[6] 3層目 / \ / a[7] a[8] a[9] 最下層
配列の添え字が0から始まっている場合、
添え字が[0]のノードは根ノードで、
添え字が[奇数]のノードは左の子ノード、
添え字が[偶数]のノードは右の子ノードです。
a[0] 根ノード / \ / \ / \ a[1] a[2] 奇数なので 偶数なので 左の子ノード 右の子ノード
配列の添え字が0から始まっている場合、
ある親の添え字を [P] とすると、
左の子の添え字は L = P×2 +1
右の子の添え字は R = P×2 +2
となります。
a[P] / \ / \ a[L] a[R] L=P×2+1 R=P×2+2
配列の添え字が0から始まっている場合、
あるノードの添え字が [C] とすると、
その親ノードの添え字 P = 小数点以下切り捨て( (C-1)÷2 )
となります。
a[P] P = 切り捨て( (L-1)÷2 ) / \ P = 切り捨て( (R-1)÷2 ) / \ a[L] a[R]
ヒープソートのソースコード
新規プロジェクトを作成し、TButton×1個、TMemo×1個 をフォームへドラッグ&ドロップします。
以下ソースコードをコピー&ペーストし、
Button1.OnClickイベントプロパティに Button1Click を設定してください。
unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; type TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; procedure Button1Click(Sender: TObject); private { Private 宣言 } public { Public 宣言 } end; var Form1: TForm1; implementation {$R *.dfm} //ヒープソートで配列を昇順に並べる(速くないがメモリやスタックを消費しない) procedure HeapSort(var Arr:Array of Integer); //二つの整数の値を入れ替える procedure SwapInt(var v1,v2:Integer); var sw:Integer; begin sw:=v1; v1:=v2; v2:=sw; end; var NoSorted:Integer;//未ソートの添え字 LeftChildIdx, RightChildIdx:integer; ParentIdx:integer; MaxParentIdx:Integer; begin //最後のノードから確定していく //処理開始時は 0~最後(NoSorted)の全てのノードがソートされていない NoSorted:=High(Arr); while NoSorted>0 do begin //未ソートノード内で子ノードが1つ以上あるノードの添え字の最大値を求める MaxParentIdx:=(NoSorted-1) div 2; for ParentIdx := MaxParentIdx downto 0 do begin //左の子ノードの添え字 LeftChildIdx:=ParentIdx*2+1; //右の子ノードの添え字 RightChildIdx:=ParentIdx*2+2; if RightChildIdx<=NoSorted then begin //左右に子がある if Arr[LeftChildIdx]>Arr[RightChildIdx] then begin //左>右 ⇒ 親と左を比較 if Arr[ParentIdx]<Arr[LeftChildIdx] then SwapInt(Arr[ParentIdx],Arr[LeftChildIdx]); end else begin //左≦右 ⇒ 親と右を比較 if Arr[ParentIdx]<Arr[RightChildIdx] then SwapInt(Arr[ParentIdx],Arr[RightChildIdx]); end; end else begin //左だけ子が存在 ⇒ 親と左を比較 if Arr[ParentIdx]<Arr[LeftChildIdx] then SwapInt(Arr[ParentIdx],Arr[LeftChildIdx]); end; end; //最大値が根ノードArr[0]に入っているので、 //根ノードArr[0]と枝ノードArr[NoSorted]を入れ替えて、枝ノードArr[NoSorted]のソートが完了 SwapInt(Arr[0], Arr[NoSorted]); //枝ノードArr[NoSorted]のソートが完了したのでNoSortedの値1つを減らす Dec(NoSorted); end; end; procedure TForm1.Button1Click(Sender: TObject); var Arr:Array of Integer; i:Integer; st:string; begin Randomize(); SetLength(Arr, 5); st:=''; for i := Low(Arr) to High(Arr) do begin Arr[i]:=Random(100); st:=st+Format('%3d',[Arr[i]]); end; Memo1.Lines.Add('ヒープソート処理前:'+st); //ヒープソート実行 HeapSort(Arr); st:=''; for i := Low(Arr) to High(Arr) do st:=st+Format('%3d',[Arr[i]]); Memo1.Lines.Add('ヒープソート処理後:'+st); end; end.