1
0
mirror of synced 2024-12-22 17:23:07 +01:00

Changed: refactored binary tree to seperate tree from data

This commit is contained in:
Mark van Renswoude 2005-01-12 14:47:32 +00:00
parent 48f62eeab7
commit 0fe601e3aa

View File

@ -14,6 +14,7 @@ type
EBTKeyExists = class(Exception); EBTKeyExists = class(Exception);
EBTKeyNotFound = class(Exception); EBTKeyNotFound = class(Exception);
EBTCursorEof = class(Exception); EBTCursorEof = class(Exception);
EBTNoCursor = class(Exception);
{** Internal representation of a binary tree node. {** Internal representation of a binary tree node.
* *
@ -45,19 +46,15 @@ type
* Trees implement a descendant to traverse through the tree. * Trees implement a descendant to traverse through the tree.
*} *}
TX2BTCustomCursor = class(TObject) TX2BTCustomCursor = class(TObject)
private
FRoot: PX2BTNode;
protected protected
function GetCurrentNode(): PX2BTNode; virtual; abstract; function GetCurrentKey(): Cardinal; virtual; abstract;
function GetEof(): Boolean; virtual; abstract; function GetEof(): Boolean; virtual; abstract;
public public
constructor Create(const ARoot: PX2BTNode); virtual;
procedure First(); virtual; abstract; procedure First(); virtual; abstract;
procedure Next(); virtual; abstract; procedure Next(); virtual; abstract;
property CurrentNode: PX2BTNode read GetCurrentNode;
property Eof: Boolean read GetEof; property Eof: Boolean read GetEof;
property CurrentKey: Cardinal read GetCurrentKey;
end; end;
TX2BTCursorClass = class of TX2BTCustomCursor; TX2BTCursorClass = class of TX2BTCustomCursor;
@ -70,39 +67,69 @@ type
*} *}
TX2BTDefaultCursor = class(TX2BTCustomCursor) TX2BTDefaultCursor = class(TX2BTCustomCursor)
private private
FRoot: PX2BTNode;
FNode: PX2BTNode; FNode: PX2BTNode;
protected protected
function GetCurrentNode(): PX2BTNode; override; function GetCurrentNode(): PX2BTNode;
function GetCurrentKey(): Cardinal; override;
function GetEof(): Boolean; override; function GetEof(): Boolean; override;
public public
constructor Create(const ARoot: PX2BTNode); virtual;
procedure First(); override; procedure First(); override;
procedure Next(); override; procedure Next(); override;
property CurrentNode: PX2BTNode read GetCurrentNode;
end; end;
{** Binary Tree implementation. {** Abstract tree manager.
* *
* Implements the basic binary tree operations, allowing room for descendants * Trees implement a descendant to manage the tree nodes. This is where the
* to implement data storage and node management. * actual tree is stored, and possibly optimized. All tree managers are
* assumed to store a 32-bit unsigned integer key with optional data.
*} *}
TX2BinaryTree = class(TObject) TX2BTCustomManager = class(TObject)
private private
FCursor: TX2BTCustomCursor; FCursor: TX2BTCustomCursor;
protected
function GetCurrentKey(): Cardinal; virtual;
function GetEof(): Boolean; virtual;
procedure CursorNeeded(); virtual; abstract;
procedure InvalidateCursor(); virtual; abstract;
property Cursor: TX2BTCustomCursor read FCursor write FCursor;
public
constructor Create(); virtual;
destructor Destroy(); override;
procedure Clear(); virtual; abstract;
procedure Insert(const AKey: Cardinal); virtual; abstract;
procedure Delete(const AKey: Cardinal); virtual; abstract;
function Exists(const AKey: Cardinal): Boolean; virtual; abstract;
function GetData(const AKey: Cardinal): Pointer; virtual; abstract;
procedure First(); virtual;
procedure Next(); virtual;
property CurrentKey: Cardinal read GetCurrentKey;
property Eof: Boolean read GetEof;
end;
TX2BTManagerClass = class of TX2BTCustomManager;
{** Default tree manager.
*}
TX2BTDefaultManager = class(TX2BTCustomManager)
private
FRoot: PX2BTNode; FRoot: PX2BTNode;
FLastNode: PX2BTNode; FLastNode: PX2BTNode;
function GetCurrentKey(): Cardinal;
function GetEof(): Boolean;
protected protected
procedure CursorNeeded(); procedure CursorNeeded(); override;
procedure InvalidateCursor(); procedure InvalidateCursor(); override;
//property Root: PX2BTNode read FRoot write FRoot;
protected
// Methods which don't really need to be virtual
// (if you have a good reason; share it with me so I can make it
// virtual, until then it's kept normal for performance reasons)
procedure ClearNodes();
function FindLowestNode(const ANode: PX2BTNode): PX2BTNode; function FindLowestNode(const ANode: PX2BTNode): PX2BTNode;
function FindHighestNode(const ANode: PX2BTNode): PX2BTNode; function FindHighestNode(const ANode: PX2BTNode): PX2BTNode;
@ -113,17 +140,31 @@ type
function RightChild(const ANode: PX2BTNode): Boolean; function RightChild(const ANode: PX2BTNode): Boolean;
procedure SwapNodes(const ANode1, ANode2: PX2BTNode); procedure SwapNodes(const ANode1, ANode2: PX2BTNode);
procedure DeleteCleanNode(var ANode: PX2BTNode); virtual;
// Virtual methods (commonly needed in descendants)
function GetCursorClass(): TX2BTCursorClass; virtual;
procedure AllocateNode(var ANode: PX2BTNode); virtual; procedure AllocateNode(var ANode: PX2BTNode); virtual;
procedure DeallocateNode(var ANode: PX2BTNode); virtual; procedure DeallocateNode(var ANode: PX2BTNode); virtual;
public
procedure Clear(); override;
procedure Insert(const AKey: Cardinal); override;
procedure Delete(const AKey: Cardinal); override;
procedure InsertNode(const AKey: Cardinal); virtual; function Exists(const AKey: Cardinal): Boolean; override;
procedure DeleteNode(const AKey: Cardinal); virtual; function GetData(const AKey: Cardinal): Pointer; override;
end;
procedure DeleteCleanNode(var ANode: PX2BTNode); virtual; {** Binary Tree implementation.
*
* Exposes the tree manager and handles node data.
*}
TX2BinaryTree = class(TObject)
private
FManager: TX2BTCustomManager;
function GetCurrentKey(): Cardinal;
function GetEof(): Boolean;
protected
function GetManagerClass(): TX2BTManagerClass; virtual;
public public
constructor Create(); virtual; constructor Create(); virtual;
destructor Destroy(); override; destructor Destroy(); override;
@ -188,13 +229,14 @@ resourcestring
RSBTKeyExists = 'The key "%d" already exists in the tree.'; RSBTKeyExists = 'The key "%d" already exists in the tree.';
RSBTKeyNotFound = 'The key "%d" could not be found in the tree.'; RSBTKeyNotFound = 'The key "%d" could not be found in the tree.';
RSBTCursorEof = 'Cursor is at Eof.'; RSBTCursorEof = 'Cursor is at Eof.';
RSBTNoCursor = 'Cursor not initialized, call First before Next.';
{====================== TX2BTCustomCursor {===================== TX2BTDefaultCursor
Initialization Traversal
========================================} ========================================}
constructor TX2BTCustomCursor.Create; constructor TX2BTDefaultCursor.Create;
begin begin
inherited Create(); inherited Create();
@ -202,9 +244,6 @@ begin
end; end;
{===================== TX2BTDefaultCursor
Traversal
========================================}
procedure TX2BTDefaultCursor.First; procedure TX2BTDefaultCursor.First;
begin begin
FNode := FRoot; FNode := FRoot;
@ -254,83 +293,79 @@ begin
Result := FNode; Result := FNode;
end; end;
function TX2BTDefaultCursor.GetCurrentKey;
begin
Result := CurrentNode^.Key;
end;
function TX2BTDefaultCursor.GetEof; function TX2BTDefaultCursor.GetEof;
begin begin
Result := not Assigned(FNode); Result := not Assigned(FNode);
end; end;
{========================== TX2BinaryTree {===================== TX2BTCustomManager
Initialization Initialization
========================================} ========================================}
constructor TX2BinaryTree.Create; constructor TX2BTCustomManager.Create;
begin begin
inherited; inherited;
end; end;
destructor TX2BinaryTree.Destroy; destructor TX2BTCustomManager.Destroy;
begin begin
ClearNodes(); Clear();
FreeAndNil(FCursor); FreeAndNil(FCursor);
inherited; inherited;
end; end;
{========================== TX2BinaryTree procedure TX2BTCustomManager.First;
Interface
========================================}
procedure TX2BinaryTree.Clear;
begin
ClearNodes();
end;
function TX2BinaryTree.Exists;
begin
Result := Assigned(FindNodeOnly(AKey));
end;
procedure TX2BinaryTree.Insert;
begin
InsertNode(AKey);
end;
procedure TX2BinaryTree.Delete;
begin
DeleteNode(AKey);
end;
procedure TX2BinaryTree.First;
begin begin
CursorNeeded(); CursorNeeded();
FCursor.First(); FCursor.First();
end; end;
procedure TX2BinaryTree.Next; procedure TX2BTCustomManager.Next;
begin begin
CursorNeeded(); CursorNeeded();
FCursor.Next(); FCursor.Next();
end; end;
{========================== TX2BinaryTree function TX2BTCustomManager.GetCurrentKey;
Internal node operations begin
if FCursor.Eof then
raise EBTCursorEof.Create(RSBTCursorEof);
Result := FCursor.CurrentKey;
end;
function TX2BTCustomManager.GetEof;
begin
Result := Assigned(FCursor) and (FCursor.Eof);
end;
{==================== TX2BTDefaultManager
Node Management
========================================} ========================================}
procedure TX2BinaryTree.AllocateNode; procedure TX2BTDefaultManager.AllocateNode;
begin begin
GetMem(ANode, SizeOf(TX2BTNode)); GetMem(ANode, SizeOf(TX2BTNode));
FillChar(ANode^, SizeOf(TX2BTNode), #0); FillChar(ANode^, SizeOf(TX2BTNode), #0);
end; end;
procedure TX2BinaryTree.DeallocateNode; procedure TX2BTDefaultManager.DeallocateNode;
begin begin
FreeMem(ANode, SizeOf(TX2BTNode)); FreeMem(ANode, SizeOf(TX2BTNode));
ANode := nil; ANode := nil;
end; end;
procedure TX2BinaryTree.ClearNodes; procedure TX2BTDefaultManager.Clear;
var var
pNode: PX2BTNode; pNode: PX2BTNode;
pParent: PX2BTNode; pParent: PX2BTNode;
@ -369,7 +404,7 @@ begin
end; end;
function TX2BinaryTree.FindHighestNode; function TX2BTDefaultManager.FindHighestNode;
begin begin
Result := ANode; Result := ANode;
@ -377,7 +412,7 @@ begin
Result := Result^.Right; Result := Result^.Right;
end; end;
function TX2BinaryTree.FindLowestNode; function TX2BTDefaultManager.FindLowestNode;
begin begin
Result := ANode; Result := ANode;
@ -385,7 +420,7 @@ begin
Result := Result^.Left; Result := Result^.Left;
end; end;
function TX2BinaryTree.FindNode; function TX2BTDefaultManager.FindNode;
var var
pNode: PX2BTNode; pNode: PX2BTNode;
@ -421,7 +456,7 @@ begin
FLastNode := Result; FLastNode := Result;
end; end;
function TX2BinaryTree.FindNodeOnly; function TX2BTDefaultManager.FindNodeOnly;
var var
pDummy: PX2BTNode; pDummy: PX2BTNode;
@ -430,19 +465,19 @@ begin
end; end;
function TX2BinaryTree.LeftChild; function TX2BTDefaultManager.LeftChild;
begin begin
Assert(Assigned(ANode^.Parent), 'Node has no parent!'); Assert(Assigned(ANode^.Parent), 'Node has no parent!');
Result := (ANode^.Parent^.Left = ANode); Result := (ANode^.Parent^.Left = ANode);
end; end;
function TX2BinaryTree.RightChild; function TX2BTDefaultManager.RightChild;
begin begin
Result := not LeftChild(ANode); Result := not LeftChild(ANode);
end; end;
procedure TX2BinaryTree.SwapNodes; procedure TX2BTDefaultManager.SwapNodes;
procedure FixLinks(const ANode, AOld: PX2BTNode); procedure FixLinks(const ANode, AOld: PX2BTNode);
begin begin
if Assigned(ANode^.Parent) then if Assigned(ANode^.Parent) then
@ -476,7 +511,7 @@ begin
end; end;
procedure TX2BinaryTree.InsertNode; procedure TX2BTDefaultManager.Insert;
var var
pNode: PX2BTNode; pNode: PX2BTNode;
pParent: PX2BTNode; pParent: PX2BTNode;
@ -505,7 +540,7 @@ begin
end; end;
end; end;
procedure TX2BinaryTree.DeleteNode; procedure TX2BTDefaultManager.Delete;
var var
pNode: PX2BTNode; pNode: PX2BTNode;
pLowest: PX2BTNode; pLowest: PX2BTNode;
@ -538,7 +573,7 @@ begin
DeleteCleanNode(pNode); DeleteCleanNode(pNode);
end; end;
procedure TX2BinaryTree.DeleteCleanNode; procedure TX2BTDefaultManager.DeleteCleanNode;
var var
pParent: PX2BTNode; pParent: PX2BTNode;
pChild: PX2BTNode; pChild: PX2BTNode;
@ -574,35 +609,97 @@ begin
end; end;
procedure TX2BinaryTree.CursorNeeded; function TX2BTDefaultManager.Exists;
begin begin
if not Assigned(FCursor) then Result := Assigned(FindNodeOnly(AKey));
FCursor := GetCursorClass().Create(FRoot);
end; end;
procedure TX2BinaryTree.InvalidateCursor; function TX2BTDefaultManager.GetData;
begin
//! Implement GetData
end;
procedure TX2BTDefaultManager.CursorNeeded;
begin
if not Assigned(FCursor) then
FCursor := TX2BTDefaultCursor.Create(FRoot);
end;
procedure TX2BTDefaultManager.InvalidateCursor;
begin begin
FreeAndNil(FCursor); FreeAndNil(FCursor);
end; end;
function TX2BinaryTree.GetCursorClass; {========================== TX2BinaryTree
Initialization
========================================}
constructor TX2BinaryTree.Create;
begin begin
Result := TX2BTDefaultCursor; inherited;
FManager := GetManagerClass().Create();
end;
destructor TX2BinaryTree.Destroy;
begin
FreeAndNil(FManager);
inherited;
end;
{========================== TX2BinaryTree
Interface
========================================}
procedure TX2BinaryTree.Clear;
begin
FManager.Clear();
end;
function TX2BinaryTree.Exists;
begin
Result := FManager.Exists(AKey);
end;
procedure TX2BinaryTree.Insert;
begin
FManager.Insert(AKey);
end;
procedure TX2BinaryTree.Delete;
begin
FManager.Delete(AKey);
end;
procedure TX2BinaryTree.First;
begin
FManager.First();
end;
procedure TX2BinaryTree.Next;
begin
FManager.Next();
end;
function TX2BinaryTree.GetManagerClass;
begin
Result := TX2BTDefaultManager;
end; end;
function TX2BinaryTree.GetCurrentKey; function TX2BinaryTree.GetCurrentKey;
begin begin
if Eof then Result := FManager.CurrentKey;
raise EBTCursorEof.Create(RSBTCursorEof);
Result := FCursor.CurrentNode^.Key;
end; end;
function TX2BinaryTree.GetEof; function TX2BinaryTree.GetEof;
begin begin
Result := Assigned(FCursor) and (FCursor.Eof); Result := FManager.Eof;
end; end;
end. end.