AVLTreeのソースコード
●avltree.pas
unit avltree;
interface
uses
SysUtils, Classes, RTLConsts;
type
TBalance = (brLeft, brEqual, brRight);
TDumpNodes = (dnPreorder, dnInorder, dnPostorder);
TAVLNode = class;
TAVLNode = class(TObject)
private
FItem : Pointer;
public
ID : Integer;
LeftChild, RightChild : TAVLNode;
Balance : TBalance;
property Item : Pointer read FItem write FItem;
constructor Create;
destructor Destroy; override;
end;
TAVLTree = class(TObject)
private
FCount : integer;
FRoot : TAVLNode;
protected
procedure AddNode(var parent : TAVLNode; newID : Integer; value : Pointer; var grow : Boolean);
procedure AdjustLeftGrow(var parent : TAVLNode);
procedure AdjustRightGrow(var parent : TAVLNode);
function Get(Index: Integer): Pointer;
function InternalGet(var parent: TAVLNode; index : integer; var bolFind:Boolean):pointer;
procedure InternalDumpNodes(var parent : TAVLNode; var s : string; search_algo:TDumpNodes);
public
procedure Add(newID : Integer; value : Pointer);
function DumpNodes(search_algo:TDumpNodes):String;
property Count : Integer read FCount;
property Items[Index: Integer]: Pointer read Get; default;
destructor Destroy; override;
end;
implementation
{ TAVLNode }
constructor TAVLNode.Create;
begin
//
end;
destructor TAVLNode.Destroy;
begin
if (LeftChild <> nil) then LeftChild.Free;
if (RightChild <> nil) then RightChild.Free;
inherited;
end;
{ TAVLTree }
//ツリーに値を追加する処理
procedure TAVLTree.Add(newID: Integer; value: Pointer);
var
grow : Boolean;
begin
//Addメソッドは、まずRootから値を追加する先を探索する
grow := False;
AddNode(FRoot, newID, value, grow);
end;
//ノードの追加を再帰的に行う処理
procedure TAVLTree.AddNode(
var parent: TAVLNode;
newID: Integer;
value : Pointer;
var grow: Boolean
);
begin
//木の最深部まで降りた場合、そこにノードを追加する
if (parent = nil) then
begin
parent := TAVLNode.Create;
parent.ID := newID;
parent.Balance := brEqual;
parent.Item := value;
grow := True;
Inc(FCount);
exit;
end;
//newIDが現在の節点のIDより小さい時の処理
//左側に下っていく
if (newID < parent.ID) then
begin
//左側へ節点を追加する
AddNode(parent.LeftChild, newID, value, grow);
//木が成長した=高さが変わった場合、grow がTrueで返ってくる
//Falseの場合、バランス調整は不要
if (grow = False) then exit;
if (parent.Balance = brRight) then
begin
//元々は右側の高さが大きかった場合
//左に新しい節点が追加されたので、これでバランスした
parent.Balance := brEqual;
//上のノードには、深度が変化していないと通知する
grow := False;
end else if (parent.Balance = brEqual) then
begin
//元々がバランスしていたので、左側に節点が追加されたため
//左側が深い状態になった
parent.Balance := brLeft;
end else
begin
//元々左側の高さが大きかったので、
//左側に節点が追加されたため、バランス調整が必要となった
AdjustLeftGrow(parent);
grow := False;
end;
end else
//newIDが現在の節点のIDより大きい場合の処理
//右側に下っていく
if (newID > parent.ID) then
begin
//右側に節点を追加する
AddNode(parent.RightChild, newID, value, grow);
//木が成長した=高さが変わった場合、grow がTrueで返ってくる
//Falseの場合、バランス調整は不要
if (grow = False) then exit;
if (parent.Balance = brLeft) then
begin
//元々は左側の高さが大きかった場合
//右に新しい節点が追加されたので、これでバランスした
parent.Balance := brEqual;
grow := False;
end else
if (parent.Balance = brEqual) then
begin
//元々がバランスしていたので、右側に節点が追加されたため
//右側が深い状態になった
parent.Balance := brRight;
end else
begin
//元々右側の高さが大きかったので
//右側に節点が追加されたため、バランス調整が必要になった
AdjustRightGrow(parent);
grow := False;
end;
end else
begin
//newIDと現在の節点のIDが同じ場合は、ノードの値を書き換える
parent.Item := value;
grow := False;
end;
end;
//ツリーの左側でバランスが崩れたときの処理
procedure TAVLTree.AdjustLeftGrow(var parent: TAVLNode);
var
OrgLeftChild, OrgGrandChild : TAVLNode;
begin
OrgLeftChild := parent.LeftChild;
if (OrgLeftChild.Balance = brLeft) then
begin
//左側の左側でバランスが崩れたので、右回転する
parent.LeftChild := OrgLeftChild.RightChild;
OrgLeftChild.RightChild := parent;
parent.Balance := brEqual;
parent := OrgLeftChild;
end else
begin
//左側の右側でバランスが崩れたので、左−右回転する
OrgGrandchild := OrgLeftchild.RightChild;
OrgLeftchild.RightChild := OrgGrandChild.LeftChild;
OrgGrandchild.LeftChild := OrgLeftchild;
parent.LeftChild := OrgGrandChild.RightChild;
OrgGrandChild.RightChild := parent;
if (OrgGrandChild.Balance = brLeft) then
parent.Balance := brRight
else
parent.Balance := brEqual;
if (OrgGrandchild.Balance = brRight) then
OrgLeftchild.Balance := brLeft
else
OrgLeftchild.Balance := brEqual;
parent := OrgGrandChild;
end;
parent.Balance := brEqual;
end;
//ツリーの右側でバランスが崩れたときの処理
procedure TAVLTree.AdjustRightGrow(var parent: TAVLNode);
var
OrgRightChild, OrgGrandChild : TAVLNode;
begin
OrgRightChild := parent.RightChild;
if (OrgRightChild.Balance = brRight) then
begin
//右側の右側でバランスが崩れたので、左回転する
parent.RightChild := OrgRightChild.LeftChild;
OrgRightChild.LeftChild := parent;
parent.Balance := brEqual;
parent := OrgRightChild;
end else
begin
//右側の左側でバランスが崩れたので、右−左回転する
OrgGrandchild := OrgRightchild.LeftChild;
OrgRightchild.LeftChild := OrgGrandChild.RightChild;
OrgGrandChild.RightChild := OrgRightChild;
parent.RightChild := OrgGrandChild.LeftChild;
OrgGrandChild.LeftChild := parent;
if (OrgGrandChild.Balance = brRight) then
parent.Balance := brLeft
else
parent.Balance := brEqual;
if (OrgGrandchild.Balance = brLeft) then
OrgRightChild.Balance := brRight
else
OrgRightChild.Balance := brEqual;
parent := OrgGrandChild;
end;
parent.Balance := brEqual;
end;
destructor TAVLTree.Destroy;
begin
if (FRoot <> nil) then FRoot.Free;
inherited;
end;
//ツリーの内部からIDを引き出して、文字列で返す
function TAVLTree.DumpNodes(search_algo:TDumpNodes): String;
begin
InternalDumpNodes(FRoot, result, search_algo);
end;
//ツリーのインデックス参照による値の取得
function TAVLTree.Get(Index: Integer): Pointer;
var
bolFind:Boolean;
begin
Result := InternalGet(FRoot, Index, bolFind);
if (bolFind = False) then raise EListError.Createfmt(LoadResString(@SListIndexError), [Index]);
end;
//ツリーの内部状態をダンプする処理
procedure TAVLTree.InternalDumpNodes(var parent: TAVLNode; var s: string; search_algo:TDumpNodes);
procedure make_result;
begin
if (s <> '') then s := s + ', ';
s := s + 'ID=' + IntToStr(parent.ID);
end;
begin
//行きがけ順はここで処理
if (search_algo = dnPreorder) then make_result;
if (parent.LeftChild <> nil) then InternalDumpNodes(parent.LeftChild, s, search_algo);
//通りがかけ順はここで処理
if (search_algo = dnInorder) then make_result;
if (parent.RightChild <> nil) then InternalDumpNodes(parent.RightChild, s, search_algo);
//帰りがけ順はここで処理
if (search_algo = dnPostorder) then make_result;
end;
//ツリーからのデータの取得を再帰的に行う処理
function TAVLTree.InternalGet(var parent: TAVLNode; index : integer; var bolFind:Boolean): pointer;
var
tmp:Pointer;
begin
if (parent.ID = Index) then
begin
result := parent.item;
bolFind := True;
exit;
end;
if (parent.LeftChild <> nil) then
begin
tmp := InternalGet(parent.LeftChild, index, bolFind);
if (bolFind = True) then
begin
result := tmp;
exit;
end;
end;
if (parent.RightChild <> nil) then
begin
tmp := InternalGet(parent.RightChild, index, bolFind);
if (bolFind = True) then
begin
result := tmp;
exit;
end;
end;
end;
end.| Index | |
| AVL木で木構造を学ぼう | |
| Page1 木構造とは何か? 木構造をたどる ロシアからやってきたAVL木 |
|
| Page2 AVL木への節点の追加 Listにそっくりな木構造のクラス アルゴリズムの実装は編み物に似ている |
|
| Appendix AVLTreeのソースコード |
|
| Delphiアルゴリズムトレーニング |
| Coding Edgeお勧め記事 |
| いまさらアルゴリズムを学ぶ意味 コーディングに役立つ! アルゴリズムの基本(1) コンピュータに「3の倍数と3の付く数字」を判断させるにはどうしたらいいか。発想力を鍛えよう |
|
| Zope 3の魅力に迫る Zope 3とは何ぞや?(1) Pythonで書かれたWebアプリケーションフレームワーク「Zope 3」。ほかのソフトウェアとは一体何が違っているのか? |
|
| 貧弱環境プログラミングのススメ 柴田 淳のコーディング天国 高性能なIT機器に囲まれた環境でコンピュータの動作原理に触れることは可能だろうか。貧弱なPC上にビットマップの直線をどうやって引く? |
|
| Haskellプログラミングの楽しみ方 のんびりHaskell(1) 関数型言語に分類されるHaskell。C言語などの手続き型言語とまったく異なるプログラミングの世界に踏み出してみよう |
|
| ちょっと変わったLisp入門 Gaucheでメタプログラミング(1) Lispの一種であるScheme。いくつかある処理系の中でも気軽にスクリプトを書けるGaucheでLispの世界を体験してみよう |
|
Coding Edge フォーラム 新着記事
- プログラムの実行はどのようにして行われるのか、Linuxカーネルのコードから探る (2017/7/20)
C言語の「Hello World!」プログラムで使われる、「printf()」「main()」関数の中身を、デバッガによる解析と逆アセンブル、ソースコード読解などのさまざまな側面から探る連載。最終回は、Linuxカーネルの中では、プログラムの起動時にはどのような処理が行われているのかを探る - エンジニアならC言語プログラムの終わりに呼び出されるexit()の中身分かってますよね? (2017/7/13)
C言語の「Hello World!」プログラムで使われる、「printf()」「main()」関数の中身を、デバッガによる解析と逆アセンブル、ソースコード読解などのさまざまな側面から探る連載。今回は、プログラムの終わりに呼び出されるexit()の中身を探る - VBAにおけるFileDialog操作の基本&ドライブの空き容量、ファイルのサイズやタイムスタンプの取得方法 (2017/7/10)
指定したドライブの空き容量、ファイルのタイムスタンプや属性を取得する方法、FileDialog/エクスプローラー操作の基本を紹介します - さらば残業! 面倒くさいエクセル業務を楽にする「Excel VBA」とは (2017/7/6)
日頃発生する“面倒くさい業務”。簡単なプログラミングで効率化できる可能性がある。本稿では、業務で使うことが多い「Microsoft Excel」で使えるVBAを紹介する。※ショートカットキー、アクセスキーの解説あり
|
|
>
Coding Edge 記事ランキング
本日
月間





