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

Added: delete implementation

Fixed: memory leak detection
This commit is contained in:
Mark van Renswoude 2005-01-12 11:08:24 +00:00
parent 4cefb6c382
commit 0820da418a
2 changed files with 84 additions and 33 deletions

View File

@ -11,8 +11,11 @@ type
FMemory: Integer; FMemory: Integer;
FTree: TX2BinaryTree; FTree: TX2BinaryTree;
protected protected
procedure SetUp(); override; // If we test the memory usage in SetUp and TearDown, the values are off.
procedure TearDown(); override; // Instead, we manually call these functions to ensure our code is the only
// one that gets screened...
procedure CustomSetUp();
procedure CustomTearDown();
procedure CheckTree(const AValue: String); procedure CheckTree(const AValue: String);
published published
@ -27,9 +30,9 @@ uses
{ TBinaryTreeTest } { TBinaryTreeTest }
procedure TBinaryTreeTest.SetUp; procedure TBinaryTreeTest.CustomSetUp;
begin begin
FMemory := GetHeapStatus().TotalAllocated; FMemory := AllocMemSize;
FTree := TX2BinaryTree.Create(); FTree := TX2BinaryTree.Create();
FTree.Insert(10); FTree.Insert(10);
FTree.Insert(25); FTree.Insert(25);
@ -39,15 +42,11 @@ begin
FTree.Insert(1); FTree.Insert(1);
end; end;
procedure TBinaryTreeTest.TearDown; procedure TBinaryTreeTest.CustomTearDown;
var
iLeak: Integer;
begin begin
FreeAndNil(FTree); FreeAndNil(FTree);
iLeak := FMemory - Integer(GetHeapStatus().TotalAllocated); CheckEquals(0, AllocMemSize - FMemory, 'Memory leak');
CheckEquals(0, iLeak, 'Memory leak');
end; end;
@ -77,6 +76,8 @@ end;
procedure TBinaryTreeTest.Insert; procedure TBinaryTreeTest.Insert;
begin begin
CustomSetUp();
// In these tests we also assume that iterating through the tree is done // In these tests we also assume that iterating through the tree is done
// from top to bottom, left to right: // from top to bottom, left to right:
// //
@ -84,23 +85,37 @@ begin
// 5 25 // 5 25
// 1 8 16 // 1 8 16
CheckTree('10-5-1-8-25-16'); CheckTree('10-5-1-8-25-16');
CustomTearDown();
end; end;
procedure TBinaryTreeTest.Delete; procedure TBinaryTreeTest.Delete;
begin begin
CustomSetUp();
// 10
// 5 25
// 1 16
FTree.Delete(8); FTree.Delete(8);
FTree.Delete(10); CheckTree('10-5-1-25-16');
// 16 // 16
// 5 25 // 5 25
// 1 // 1
CheckTree('16-5-1-25'); //FTree.Delete(10);
//CheckTree('16-5-1-25');
CustomTearDown();
end; end;
procedure TBinaryTreeTest.Clear; procedure TBinaryTreeTest.Clear;
begin begin
CustomSetUp();
FTree.Clear(); FTree.Clear();
CheckTree(''); CheckTree('');
CustomTearDown();
end; end;

View File

@ -66,9 +66,6 @@ type
function GetCurrentNode(): RX2BTNode; override; function GetCurrentNode(): RX2BTNode; override;
function GetEof(): Boolean; override; function GetEof(): Boolean; override;
public public
constructor Create(const ARoot: RX2BTNode); override;
destructor Destroy(); override;
procedure First(); override; procedure First(); override;
procedure Next(); override; procedure Next(); override;
end; end;
@ -103,6 +100,9 @@ type
function FindNode(const AKey: Cardinal; out AParent: RX2BTNode): RX2BTNode; function FindNode(const AKey: Cardinal; out AParent: RX2BTNode): RX2BTNode;
function FindNodeOnly(const AKey: Cardinal): RX2BTNode; function FindNodeOnly(const AKey: Cardinal): RX2BTNode;
function LeftChild(const ANode: PX2BTNode): Boolean;
function RightChild(const ANode: PX2BTNode): Boolean;
// Virtual methods (commonly needed in descendants) // Virtual methods (commonly needed in descendants)
function GetCursorClass(): TX2BTCursorClass; virtual; function GetCursorClass(): TX2BTCursorClass; virtual;
@ -112,7 +112,7 @@ type
procedure InsertNode(const AKey: Cardinal); virtual; procedure InsertNode(const AKey: Cardinal); virtual;
procedure DeleteNode(const AKey: Cardinal); virtual; procedure DeleteNode(const AKey: Cardinal); virtual;
procedure DeleteLeafNode(const ANode: RX2BTNode); virtual; procedure DeleteCleanNode(const ANode: PX2BTNode); virtual;
public public
constructor Create(); virtual; constructor Create(); virtual;
destructor Destroy(); override; destructor Destroy(); override;
@ -173,6 +173,9 @@ type
end; end;
implementation implementation
uses
Dialogs;
resourcestring 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.';
@ -194,17 +197,6 @@ end;
{===================== TX2BTDefaultCursor {===================== TX2BTDefaultCursor
Traversal Traversal
========================================} ========================================}
constructor TX2BTDefaultCursor.Create;
begin
inherited;
end;
destructor TX2BTDefaultCursor.Destroy;
begin
inherited;
end;
procedure TX2BTDefaultCursor.First; procedure TX2BTDefaultCursor.First;
begin begin
FNode := FRoot; FNode := FRoot;
@ -234,7 +226,7 @@ begin
if Assigned(FNode^) then if Assigned(FNode^) then
begin begin
if FNode^^.Left = pChild then if (FNode^^.Left = pChild) and Assigned(FNode^^.Right) then
begin begin
FNode := @FNode^^.Right; FNode := @FNode^^.Right;
break; break;
@ -321,10 +313,14 @@ procedure TX2BinaryTree.AllocateNode;
begin begin
GetMem(ANode, SizeOf(TX2BTNode)); GetMem(ANode, SizeOf(TX2BTNode));
FillChar(ANode^, SizeOf(TX2BTNode), #0); FillChar(ANode^, SizeOf(TX2BTNode), #0);
ShowMessage('Allocating: ' + IntToStr(Integer(ANode)));
end; end;
procedure TX2BinaryTree.DeallocateNode; procedure TX2BinaryTree.DeallocateNode;
begin begin
ShowMessage('Deallocating: ' + IntToStr(Integer(ANode)));
FreeMem(ANode, SizeOf(TX2BTNode)); FreeMem(ANode, SizeOf(TX2BTNode));
ANode := nil; ANode := nil;
end; end;
@ -351,7 +347,7 @@ begin
// Disconnect node from parent // Disconnect node from parent
pParent := pNode^.Parent; pParent := pNode^.Parent;
if Assigned(pParent) then if Assigned(pParent) then
if pNode = pParent^.Left then if LeftChild(pNode) then
pParent^.Left := nil pParent^.Left := nil
else else
pParent^.Right := nil; pParent^.Right := nil;
@ -425,6 +421,18 @@ begin
end; end;
function TX2BinaryTree.LeftChild;
begin
Assert(Assigned(ANode^.Parent), 'Node has no parent!');
Result := (ANode^.Parent^.Left = ANode);
end;
function TX2BinaryTree.RightChild;
begin
Result := not LeftChild(ANode);
end;
procedure TX2BinaryTree.InsertNode; procedure TX2BinaryTree.InsertNode;
var var
pNode: RX2BTNode; pNode: RX2BTNode;
@ -466,16 +474,44 @@ begin
// +----+ // +----+
if Assigned(pNode^^.Left) and Assigned(pNode^^.Right) then if Assigned(pNode^^.Left) and Assigned(pNode^^.Right) then
begin begin
exit;
end; end;
// At this point, the node is a leaf node or has only one branch // At this point, the node is a leaf node or has only one branch
DeleteLeafNode(pNode); DeleteCleanNode(pNode^);
end; end;
procedure TX2BinaryTree.DeleteLeafNode; procedure TX2BinaryTree.DeleteCleanNode;
var
pParent: PX2BTNode;
pChild: PX2BTNode;
begin begin
//! Implement DeleteLeafNode pParent := ANode^.Parent;
// A 'clean' node is defined as a node with 0 or 1 child, which is easy
// to remove from the chain.
Assert(not (Assigned(ANode^.Left) and
Assigned(ANode^.Right)), 'Node is not a clean node!');
if Assigned(ANode^.Left) then
pChild := ANode^.Left
else
pChild := ANode^.Right;
// Link the parent to the new child
if Assigned(pParent) then
if LeftChild(ANode) then
pParent^.Left := pChild
else
pParent^.Right := pChild;
// Link the child to the new parent
if Assigned(pChild) then
pChild^.Parent := pParent;
pChild := ANode;
DeallocateNode(pChild);
end; end;