Changed: refactored binary tree to seperate tree from data
This commit is contained in:
parent
48f62eeab7
commit
0fe601e3aa
279
X2UtTrees.pas
279
X2UtTrees.pas
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user