1
0
mirror of synced 2024-09-19 09:46:09 +00:00

Merged: avltree branch

This commit is contained in:
Mark van Renswoude 2004-08-20 10:03:59 +00:00
parent d3ae64e43d
commit b105c57f5b
8 changed files with 777 additions and 175 deletions

33
Test/Forms/FBTree.dfm Normal file
View File

@ -0,0 +1,33 @@
object frmBTree: TfrmBTree
Left = 199
Top = 107
Width = 603
Height = 410
Caption = 'Binary Tree Debug'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object ocTree: TdxOrgChart
Left = 0
Top = 0
Width = 595
Height = 383
DefaultNodeWidth = 50
BorderStyle = bsNone
Options = [ocSelect, ocRect3D]
Align = alClient
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
ParentColor = True
OnDblClick = ocTreeDblClick
end
end

129
Test/Forms/FBTree.pas Normal file
View File

@ -0,0 +1,129 @@
unit FBTree;
interface
uses
Forms,
Classes,
Controls,
Windows,
dxorgchr,
X2UtBinaryTree;
type
TfrmBTree = class(TForm)
ocTree: TdxOrgChart;
procedure ocTreeDblClick(Sender: TObject);
private
FTree: TX2UtCustomBTree;
protected
procedure BuildTree(const ARoot: PX2UtBTreeNode;
const AParent: TdxOcNode = nil);
public
class procedure Execute(const ATree: TX2UtCustomBTree;
const AShowModal: Boolean = True);
end;
implementation
uses
Graphics,
SysUtils,
TypInfo;
type
THackBTree = class(TX2UtCustomBTree);
{$R *.dfm}
class procedure TfrmBTree.Execute;
begin
with TfrmBTree.Create(nil) do
try
FTree := ATree;
BuildTree(THackBTree(ATree).Root);
if Assigned(ocTree.RootNode) then
ocTree.RootNode.Expand(True);
if AShowModal then
ShowModal()
else
Show();
finally
// Yes, yes, memory leak I know. Should have an owner of something. Anyways,
// I'm too lazy to fix it in this test application...
if AShowModal then
Free();
end;
end;
procedure TfrmBTree.BuildTree;
function CreateTextNode(const AParent: TdxOcNode;
const AText: String): TdxOcNode;
begin
Result := ocTree.AddChild(AParent, nil);
Result.Text := AText;
Result.Color := clInfoBk;
end;
function CreateNode(const AParent: TdxOcNode;
const ANode: PX2UtBTreeNode): TdxOcNode;
begin
Result := CreateTextNode(AParent, IntToStr(ANode^.Index) + #13#10 +
IntToStr(ANode^.Balance));
Result.Data := ANode;
end;
var
pNode: TdxOcNode;
pLeft: TdxOcNode;
pRight: TdxOcNode;
begin
if not Assigned(ARoot) then
exit;
pLeft := nil;
pRight := nil;
if not Assigned(AParent) then
pNode := CreateNode(nil, ARoot)
else
pNode := AParent;
if Assigned(ARoot^.Children[0]) then
pLeft := CreateNode(pNode, ARoot^.Children[0])
else if Assigned(ARoot^.Children[1]) then
CreateTextNode(pNode, '<nil>');
if Assigned(ARoot^.Children[1]) then
pRight := CreateNode(pNode, ARoot^.Children[1])
else if Assigned(ARoot^.Children[0]) then
CreateTextNode(pNode, '<nil>');
if Assigned(ARoot^.Children[0]) then
BuildTree(ARoot^.Children[0], pLeft);
if Assigned(ARoot^.Children[1]) then
BuildTree(ARoot^.Children[1], pRight);
end;
procedure TfrmBTree.ocTreeDblClick;
var
pNode: TdxOcNode;
begin
pNode := ocTree.Selected;
if Assigned(pNode) and Assigned(pNode.Data) then
begin
FTree.Delete(PX2UtBTreeNode(pNode.Data)^.Index);
ocTree.Clear();
BuildTree(THackBTree(FTree).Root);
if Assigned(ocTree.RootNode) then
ocTree.RootNode.Expand(True);
end;
end;
end.

View File

@ -32,6 +32,6 @@
-M -M
-$M16384,1048576 -$M16384,1048576
-K$00400000 -K$00400000
-LE"c:\program files\borland\delphi6\Projects\Bpl" -LE"c:\delphi6\Projects\Bpl"
-LN"c:\program files\borland\delphi6\Projects\Bpl" -LN"c:\delphi6\Projects\Bpl"
-DmadExcept -DmadExcept

View File

@ -46,7 +46,7 @@ UnitOutputDir=
PackageDLLOutputDir= PackageDLLOutputDir=
PackageDCPOutputDir= PackageDCPOutputDir=
SearchPath= SearchPath=
Packages=vcl;rtl;dbrtl;vcldb;vclx;dss;dsnapcrba;dsnapcon;inetdb;webdsnap;websnap;dbxcds;Irc;parsdpk;hotspotter Packages=vcl;rtl;dbrtl;vcldb;vclx;dss;dsnapcrba;dsnapcon;inetdb;webdsnap;websnap;dbxcds;Irc;parsdpk;hotspotter;dxorgcD6
Conditionals=madExcept Conditionals=madExcept
DebugSourceDirs= DebugSourceDirs=
UsePackages=0 UsePackages=0
@ -56,6 +56,10 @@ HostApplication=
Launcher= Launcher=
UseLauncher=0 UseLauncher=0
DebugCWD= DebugCWD=
[Language]
ActiveLang=
ProjectLang=
RootDir=
[Version Info] [Version Info]
IncludeVerInfo=0 IncludeVerInfo=0
AutoIncBuild=0 AutoIncBuild=0
@ -184,16 +188,7 @@ c:\program files\borland\delphi6\Bin\dclwebsnap60.bpl=Borland WebSnap Components
c:\program files\borland\delphi6\Bin\dclite60.bpl=Borland Integrated Translation Environment c:\program files\borland\delphi6\Bin\dclite60.bpl=Borland Integrated Translation Environment
c:\program files\borland\delphi6\Bin\dcldbx60.bpl=Borland dbExpress Components c:\program files\borland\delphi6\Bin\dcldbx60.bpl=Borland dbExpress Components
c:\program files\borland\delphi6\Bin\dcldbxcds60.bpl=Borland Local DBX ClientDataset Components c:\program files\borland\delphi6\Bin\dcldbxcds60.bpl=Borland Local DBX ClientDataset Components
[Included Packages] <<<<<<< .working
C:\Program Files\Borland\Delphi6\Bin\dclstd60.bpl=Borland Standard Components =======
c:\program files\borland\delphi6\Bin\dclsmpedit60.bpl=Borland Editor Script Enhancements F:\Delphi\Components\DevExpress\OrgChart Suite\Lib\dcldxDBOrD6.bpl=ExpressDBOrgChart by Developer Express Inc.
C:\Program Files\Borland\Delphi6\Bin\dcldb60.bpl=Borland Database Components >>>>>>> .merge-right.r40
C:\Program Files\Borland\Delphi6\Bin\dclact60.bpl=Borland ActionBar Components
F:\Delphi\Components\madCollection\madBasic\Delphi 6\madBasic_.bpl=madBasic 1.1f · www.madshi.net
F:\Delphi\Components\madCollection\madDisAsm\Delphi 6\madDisAsm_.bpl=madDisAsm 2.0a · www.madshi.net
F:\Delphi\Components\madCollection\madExcept\Delphi 6\madExcept_.bpl=madExcept 2.6a · www.madshi.net
F:\Delphi\Components\madCollection\madExcept\Delphi 6\madExceptWizard_.bpl=madExceptWizard 2.6 · www.madshi.net
c:\program files\borland\delphi6\Bin\dclcds60.bpl=Borland Base Cached ClientDataset Component
C:\Program Files\Borland\Delphi6\Bin\dclmid60.bpl=Borland MyBase DataAccess Components
C:\PROGRA~1\Borland\Delphi6\Projects\Bpl\ThemeManager6.bpl=Windows XP Theme Manager
H:\Downloads\commentexpert.bpl=Comment Expert v1.0 Alpha

View File

@ -7,9 +7,11 @@ uses
madLinkDisAsm, madLinkDisAsm,
SysUtils, SysUtils,
X2UtHashes, X2UtHashes,
X2UtBinaryTree; X2UtBinaryTree,
FBTree in 'Forms\FBTree.pas' {frmBTree};
<<<<<<< .working
procedure DebugBTree(const ANode: PX2UtBTreeNode; const AIndent: Integer = 0); procedure DebugBTree(const ANode: PX2UtBTreeNode; const AIndent: Integer = 0);
begin begin
WriteLn(StringOfChar(' ', AIndent), ANode^.Index); WriteLn(StringOfChar(' ', AIndent), ANode^.Index);
@ -25,6 +27,8 @@ end;
type type
THackBTree = class(TX2UtCustomBTree); THackBTree = class(TX2UtCustomBTree);
=======
>>>>>>> .merge-right.r40
var var
shData: TX2UtStringHash; shData: TX2UtStringHash;
btTest: TX2UtStringBTree; btTest: TX2UtStringBTree;
@ -37,25 +41,32 @@ begin
btTest := TX2UtStringBTree.Create(); btTest := TX2UtStringBTree.Create();
try try
Randomize(); Randomize();
for iItem := 0 to 31 do for iItem := 0 to 61 do
btTest[Random(500)] := 'bla'; btTest[Random(500)] := 'bla';
<<<<<<< .working
btTest[300] := 'bla'; btTest[300] := 'bla';
btTest.Delete(300); btTest.Delete(300);
=======
TfrmBTree.Execute(btTest);
>>>>>>> .merge-right.r40
<<<<<<< .working
// Heh, hacking my own class. This is just for debugging the tree, // Heh, hacking my own class. This is just for debugging the tree,
// there should never be any need to access the root node outside of the // there should never be any need to access the root node outside of the
// class otherwise, so I made it protected. // class otherwise, so I made it protected.
pItem := THackBTree(btTest).Root; pItem := THackBTree(btTest).Root;
DebugBTree(pItem); DebugBTree(pItem);
=======
>>>>>>> .merge-right.r40
WriteLn; WriteLn;
btTest.Reset(); btTest.Reset();
while btTest.Next() do while btTest.Next() do
WriteLn(btTest.CurrentIndex, ' - ', btTest.CurrentValue); WriteLn(btTest.CurrentIndex, ' - ', btTest.CurrentValue);
finally finally
FreeAndNil(btTest); FreeAndNil(btTest);
ReadLn; //ReadLn;
end; end;
} }
@ -64,12 +75,16 @@ begin
shData['thisakslhalskdjfhaslkdfjhaslkfjh'] := 'is'; shData['thisakslhalskdjfhaslkdfjhaslkfjh'] := 'is';
shData['a'] := 'test'; shData['a'] := 'test';
TfrmBTree.Execute(shData);
{
shData.Reset(); shData.Reset();
while shData.Next() do while shData.Next() do
WriteLn(shData.CurrentKey, ': ', shData.CurrentValue, ' (', WriteLn(shData.CurrentKey, ': ', shData.CurrentValue, ' (',
shData[shData.CurrentKey], ')'); shData[shData.CurrentKey], ')');
}
finally finally
FreeAndNil(shData); FreeAndNil(shData);
ReadLn; //ReadLn;
end; end;
end. end.

View File

@ -97,10 +97,8 @@ begin
} }
// Test for the definitions // Test for the definitions
{
Settings.Define('Test', 'Value', 5, [[0, 5], [10, 15]]); Settings.Define('Test', 'Value', 5, [[0, 5], [10, 15]]);
Settings.ReadInteger('Test', 'Value'); Settings.ReadInteger('Test', 'Value');
}
TraverseSection(Settings, '', 1); TraverseSection(Settings, '', 1);
WriteLn; WriteLn;

View File

@ -9,6 +9,9 @@
:: convenience reasons I will however ignore your ranting and call my :: convenience reasons I will however ignore your ranting and call my
:: classes "TX2UtBTree". ;) :: classes "TX2UtBTree". ;)
:: ::
:: This unit contains code based on GNU libavl:
:: http://www.msu.edu/~pfaffben/avl/libavl.html/
::
:: Last changed: $Date$ :: Last changed: $Date$
:: Revision: $Rev$ :: Revision: $Rev$
:: Author: $Author$ :: Author: $Author$
@ -17,9 +20,8 @@ unit X2UtBinaryTree;
interface interface
uses uses
SysUtils, SysUtils;
VirtualTrees;
type type
//:$ Raised when the cursor is invalid. //:$ Raised when the cursor is invalid.
//:: Call Reset on the binary tree to create a valid cursor. //:: Call Reset on the binary tree to create a valid cursor.
@ -28,31 +30,48 @@ type
{ {
:$ Internal representation of a node. :$ Internal representation of a node.
} }
PX2UtBTreeNode = ^TX2UtBTreeNode; PPX2UtBTreeNode = ^PX2UtBTreeNode;
TX2UtBTreeNode = record PX2UtBTreeNode = ^TX2UtBTreeNode;
TX2UtBTreeNode = record
Index: Cardinal; Index: Cardinal;
Parent: PX2UtBTreeNode; Children: array[0..1] of PX2UtBTreeNode;
Left: PX2UtBTreeNode; Balance: Integer;
Right: PX2UtBTreeNode;
Data: record end; Data: record end;
end; end;
{ {
:$ Internal parent stack :$ Internal node stack
} }
TX2UtBTreeStack = class(TObject) TX2UtBTreeStackItem = record
Node: PX2UtBTreeNode;
Direction: Integer;
end;
TX2UtBTreeStack = class(TObject)
private private
FItems: array of PX2UtBTreeNode; FItems: array of TX2UtBTreeStackItem;
FCount: Integer; FCount: Integer;
FPosition: Integer; FPosition: Integer;
function GetCount(): Integer;
function GetNode(Index: Integer): PX2UtBTreeNode;
function GetDirection(Index: Integer): Integer;
procedure SetDirection(Index: Integer; const Value: Integer);
procedure SetNode(Index: Integer; const Value: PX2UtBTreeNode);
public public
constructor Create(); constructor Create();
procedure Clear(); procedure Clear();
procedure Push(const ANode: PX2UtBTreeNode); procedure Push(const ANode: PX2UtBTreeNode; const ADirection: Integer = 0);
function Pop(): PX2UtBTreeNode; function Pop(): PX2UtBTreeNode; overload;
function Pop(var ADirection: Integer): PX2UtBTreeNode; overload;
procedure Reverse(); property Node[Index: Integer]: PX2UtBTreeNode read GetNode
write SetNode; default;
property Direction[Index: Integer]: Integer read GetDirection
write SetDirection;
property Count: Integer read GetCount;
end; end;
{ {
@ -63,10 +82,11 @@ type
} }
TX2UtCustomBTree = class(TObject) TX2UtCustomBTree = class(TObject)
private private
FCount: Integer;
FRoot: PX2UtBTreeNode; FRoot: PX2UtBTreeNode;
FCursor: PX2UtBTreeNode; FCursor: PX2UtBTreeNode;
FIsReset: Boolean; FIsReset: Boolean;
FParent: TX2UtBTreeStack; FParents: TX2UtBTreeStack;
FNodeSize: Cardinal; FNodeSize: Cardinal;
FDataSize: Cardinal; FDataSize: Cardinal;
@ -74,12 +94,31 @@ type
function GetTotalSize(): Cardinal; function GetTotalSize(): Cardinal;
protected protected
function GetCurrentIndex(): Cardinal; function GetCurrentIndex(): Cardinal;
function GetNodeData(const ANode: PX2UtBTreeNode): Pointer; virtual; function GetNodeData(const ANode: PX2UtBTreeNode): Pointer; virtual;
procedure CopyNodeData(const ASource, ADest: PX2UtBTreeNode);
procedure BalanceInsert(var ANode: PX2UtBTreeNode);
function LookupNode(const AIndex: Cardinal; function LookupNode(const AIndex: Cardinal;
const ACanCreate: Boolean = False; const ACanCreate: Boolean = False;
const ASetCursor: Boolean = False): PX2UtBTreeNode; const ASetCursor: Boolean = False): PX2UtBTreeNode;
procedure RotateLeft(var ANode: PX2UtBTreeNode);
procedure RotateRight(var ANode: PX2UtBTreeNode);
function DeleteLeftShrunk(var ANode: PX2UtBTreeNode): Integer;
function DeleteRightShrunk(var ANode: PX2UtBTreeNode): Integer;
function DeleteFindHighest(const ATarget: PX2UtBTreeNode;
var ANode: PX2UtBTreeNode;
out AResult: Integer): Boolean;
function DeleteFindLowest(const ATarget: PX2UtBTreeNode;
var ANode: PX2UtBTreeNode;
out AResult: Integer): Boolean;
function InternalDeleteNode(var ARoot: PX2UtBTreeNode;
const AIndex: Cardinal): Integer;
procedure DeleteNode(const AIndex: Cardinal);
procedure InitNode(var ANode: PX2UtBTreeNode); virtual; procedure InitNode(var ANode: PX2UtBTreeNode); virtual;
procedure FreeNode(var ANode: PX2UtBTreeNode); virtual; procedure FreeNode(var ANode: PX2UtBTreeNode); virtual;
@ -89,7 +128,7 @@ type
property Cursor: PX2UtBTreeNode read FCursor write FCursor; property Cursor: PX2UtBTreeNode read FCursor write FCursor;
property Root: PX2UtBTreeNode read FRoot; property Root: PX2UtBTreeNode read FRoot;
property IsReset: Boolean read FIsReset write FIsReset; property IsReset: Boolean read FIsReset write FIsReset;
property Parent: TX2UtBTreeStack read FParent; property Parents: TX2UtBTreeStack read FParents;
property NodeSize: Cardinal read FNodeSize; property NodeSize: Cardinal read FNodeSize;
property TotalSize: Cardinal read GetTotalSize; property TotalSize: Cardinal read GetTotalSize;
@ -128,6 +167,9 @@ type
//:! The order in which nodes are traversed is from top to bottom, left //:! The order in which nodes are traversed is from top to bottom, left
//:! to right. Do not depend on the binary tree to sort the output. //:! to right. Do not depend on the binary tree to sort the output.
function Next(): Boolean; virtual; function Next(): Boolean; virtual;
//:$ Contains the number of nodes in the tree
property Count: Integer read FCount;
end; end;
{ {
@ -203,6 +245,12 @@ resourcestring
const const
CStackSize = 32; CStackSize = 32;
CLeft = 0;
CRight = 1;
CError = 0;
COK = 1;
CBalance = 2;
{======================== TX2UtBTreeStack {======================== TX2UtBTreeStack
@ -234,39 +282,64 @@ begin
SetLength(FItems, FCount); SetLength(FItems, FCount);
end; end;
FItems[FPosition] := ANode; with FItems[FPosition] do
begin
Node := ANode;
Direction := ADirection;
end;
end; end;
function TX2UtBTreeStack.Pop; function TX2UtBTreeStack.Pop(): PX2UtBTreeNode;
begin begin
Result := nil; Result := nil;
if FPosition > -1 then if FPosition >= 0 then
begin begin
Result := FItems[FPosition]; Result := FItems[FPosition].Node;
Dec(FPosition); Dec(FPosition);
end; end;
end; end;
function TX2UtBTreeStack.Pop(var ADirection: Integer): PX2UtBTreeNode;
procedure TX2UtBTreeStack.Reverse;
var
iCount: Integer;
iIndex: Integer;
pSwap: PX2UtBTreeNode;
begin begin
if FPosition = -1 then Result := nil;
exit; if FPosition >= 0 then
iCount := (FPosition + 1) div 2;
for iIndex := 0 to iCount - 1 do
begin begin
pSwap := FItems[iIndex]; ADirection := FItems[FPosition].Direction;
FItems[iIndex] := FItems[FPosition - iIndex]; Result := FItems[FPosition].Node;
FItems[FPosition - iIndex] := pSwap; Dec(FPosition);
end; end;
end; end;
function TX2UtBTreeStack.GetNode;
begin
Assert((Index >= 0) and (Index <= FPosition), '* BUG * Invalid stack index!');
Result := FItems[Index].Node;
end;
procedure TX2UtBTreeStack.SetNode;
begin
Assert((Index >= 0) and (Index <= FPosition), '* BUG * Invalid stack index!');
FItems[Index].Node := Value;
end;
function TX2UtBTreeStack.GetDirection;
begin
Assert((Index >= 0) and (Index <= FPosition), '* BUG * Invalid stack index!');
Result := FItems[Index].Direction;
end;
procedure TX2UtBTreeStack.SetDirection;
begin
Assert((Index >= 0) and (Index <= FPosition), '* BUG * Invalid stack index!');
FItems[Index].Direction := Value;
end;
function TX2UtBTreeStack.GetCount;
begin
Result := FPosition + 1;
end;
{======================= TX2UtCustomBTree {======================= TX2UtCustomBTree
Initialization Initialization
@ -275,16 +348,14 @@ constructor TX2UtCustomBTree.Create;
begin begin
inherited; inherited;
FParent := TX2UtBTreeStack.Create(); FParents := TX2UtBTreeStack.Create();
FNodeSize := SizeOf(TX2UtBTreeNode); FNodeSize := SizeOf(TX2UtBTreeNode);
end; end;
destructor TX2UtCustomBTree.Destroy; destructor TX2UtCustomBTree.Destroy;
begin begin
FreeAndNil(FParent); FreeAndNil(FParents);
Clear();
if Assigned(FRoot) then
FreeNode(FRoot);
inherited; inherited;
end; end;
@ -299,87 +370,463 @@ begin
Result := Pointer(Cardinal(ANode) + NodeSize); Result := Pointer(Cardinal(ANode) + NodeSize);
end; end;
function TX2UtCustomBTree.LookupNode; procedure TX2UtCustomBTree.CopyNodeData;
begin
ADest^.Index := ASource^.Index;
Move(GetNodeData(ASource)^,
GetNodeData(ADest)^,
DataSize);
end;
procedure TX2UtCustomBTree.BalanceInsert;
var var
pNode: PX2UtBTreeNode; pNode: PX2UtBTreeNode;
pSwap: PX2UtBTreeNode;
begin begin
Result := nil; if ANode^.Balance = -2 then
if not Assigned(FRoot) then
begin begin
if ACanCreate then // Left-heavy
begin pNode := ANode^.Children[CLeft];
InitNode(FRoot);
FRoot^.Index := AIndex;
Result := FRoot;
if ASetCursor then if pNode^.Balance = -1 then
begin begin
Parent.Clear(); pSwap := pNode;
Cursor := FRoot; ANode^.Children[CLeft] := pNode^.Children[CRight];
pNode^.Children[CRight] := ANode;
pNode^.Balance := 0;
ANode^.Balance := 0;
end else
begin
Assert(pNode^.Balance = 1, '* BUG * Unexpected node balance');
pSwap := pNode^.Children[CRight];
pNode^.Children[CRight] := pSwap^.Children[CLeft];
pSwap^.Children[CLeft] := pNode;
ANode^.Children[CLeft] := pSwap^.Children[CRight];
pSwap^.Children[CRight] := ANode;
case pSwap^.Balance of
-1:
begin
pNode^.Balance := 0;
ANode^.Balance := 1;
end;
0:
begin
pNode^.Balance := 0;
ANode^.Balance := 0;
end;
else
pNode^.Balance := -1;
ANode^.Balance := 0;
end; end;
pSwap^.Balance := 0;
end; end;
ANode := pSwap;
end else if ANode^.Balance = 2 then
begin
// Right-heavy
pNode := ANode^.Children[CRight];
if pNode^.Balance = 1 then
begin
pSwap := pNode;
ANode^.Children[CRight] := pNode^.Children[CLeft];
pNode^.Children[CLeft] := ANode;
pNode^.Balance := 0;
ANode^.Balance := 0;
end else
begin
Assert(pNode^.Balance = -1, '* BUG * Unexpected node balance');
pSwap := pNode^.Children[CLeft];
pNode^.Children[CLeft] := pSwap^.Children[CRight];
pSwap^.Children[CRight] := pNode;
ANode^.Children[CRight] := pSwap^.Children[CLeft];
pSwap^.Children[CLeft] := ANode;
case pSwap^.Balance of
1:
begin
pNode^.Balance := 0;
ANode^.Balance := -1;
end;
0:
begin
pNode^.Balance := 0;
ANode^.Balance := 0;
end;
else
pNode^.Balance := 1;
ANode^.Balance := 0;
end;
pSwap^.Balance := 0;
end;
ANode := pSwap;
end;
end;
function TX2UtCustomBTree.LookupNode;
var
pCurrent: PPX2UtBTreeNode;
pBalance: PPX2UtBTreeNode;
pLast: PX2UtBTreeNode;
pNode: PX2UtBTreeNode;
pPath: TX2UtBTreeStack;
begin
Result := nil;
if ASetCursor then
Parents.Clear();
pPath := TX2UtBTreeStack.Create();
try
pCurrent := @FRoot;
pBalance := nil;
repeat
if Assigned(pCurrent^) then
begin
pPath.Push(pCurrent^);
if pCurrent^^.Balance <> 0 then
pBalance := pCurrent;
if AIndex > pCurrent^^.Index then
// Continue on the right side
pCurrent := @pCurrent^^.Children[CRight]
else if AIndex < pCurrent^^.Index then
// Continue on the left side
pCurrent := @pCurrent^^.Children[CLeft]
else
begin
// Found it!
Result := pCurrent^;
break;
end;
end else if ACanCreate then
begin
// Create new node
InitNode(pCurrent^);
pCurrent^^.Index := AIndex;
// Update balance factors
pLast := pCurrent^;
pNode := pPath.Pop();
while Assigned(pNode) do
begin
if pNode^.Children[CLeft] = pLast then
Dec(pNode^.Balance)
else
Inc(pNode^.Balance);
if Assigned(pBalance) and (pNode = pBalance^) then
break;
pLast := pNode;
pNode := pPath.Pop();
end;
if Assigned(pBalance) then
BalanceInsert(pBalance^);
break;
end else
break;
until False;
finally
FreeAndNil(pPath);
end;
end;
procedure TX2UtCustomBTree.RotateLeft;
var
pSwap: PX2UtBTreeNode;
begin
pSwap := ANode;
ANode := ANode^.Children[CRight];
pSwap^.Children[CRight] := ANode^.Children[CLeft];
ANode^.Children[CLeft] := pSwap;
end;
procedure TX2UtCustomBTree.RotateRight;
var
pSwap: PX2UtBTreeNode;
begin
pSwap := ANode;
ANode := ANode^.Children[CLeft];
pSwap^.Children[CLeft] := ANode^.Children[CRight];
ANode^.Children[CRight] := pSwap;
end;
function TX2UtCustomBTree.DeleteLeftShrunk;
begin
case ANode^.Balance of
-1:
begin
ANode^.Balance := 0;
Result := CBalance;
end;
0:
begin
ANode^.Balance := 1;
Result := COK;
end;
1:
begin
case ANode^.Children[CRight]^.Balance of
1:
begin
if ANode^.Children[CRight]^.Balance = 0 then
ANode^.Balance := 1
else
ANode^.Balance := 0;
RotateLeft(ANode);
Result := CBalance;
end;
0:
begin
ANode^.Balance := 1;
ANode^.Children[CRight]^.Balance := -1;
RotateLeft(ANode);
Result := COK;
end;
-1:
begin
case ANode^.Children[CRight]^.Children[CLeft]^.Balance of
-1:
begin
ANode^.Balance := 0;
ANode^.Children[CRight]^.Balance := 1;
end;
0:
begin
ANode^.Balance := 0;
ANode^.Children[CRight]^.Balance := 0;
end;
1:
begin
ANode^.Balance := -1;
ANode^.Children[CRight]^.Balance := 0;
end;
end;
ANode^.Children[CRight]^.Children[CLeft]^.Balance := 0;
RotateRight(ANode^.Children[CRight]);
RotateLeft(ANode);
Result := CBalance;
end;
end;
end;
end;
end;
function TX2UtCustomBTree.DeleteRightShrunk;
begin
case ANode^.Balance of
1:
begin
ANode^.Balance := 0;
Result := CBalance;
end;
0:
begin
ANode^.Balance := -1;
Result := COK;
end;
-1:
begin
case ANode^.Children[CLeft]^.Balance of
-1:
begin
if ANode^.Children[CLeft]^.Balance = 0 then
ANode^.Balance := 1
else
ANode^.Balance := 0;
RotateRight(ANode);
Result := CBalance;
end;
0:
begin
ANode^.Balance := -1;
ANode^.Children[CLeft]^.Balance := 1;
RotateRight(ANode);
Result := COK;
end;
1:
begin
case ANode^.Children[CLeft]^.Children[CRight]^.Balance of
-1:
begin
ANode^.Balance := 1;
ANode^.Children[CLeft]^.Balance := 0;
end;
0:
begin
ANode^.Balance := 0;
ANode^.Children[CLeft]^.Balance := 0;
end;
1:
begin
ANode^.Balance := 1;
ANode^.Children[CLeft]^.Balance := 0;
end;
end;
ANode^.Children[CLeft]^.Children[CRight]^.Balance := 0;
RotateLeft(ANode^.Children[CLeft]);
RotateRight(ANode);
Result := CBalance;
end;
end;
end;
end;
end;
function TX2UtCustomBTree.DeleteFindHighest;
var
pSwap: PX2UtBTreeNode;
begin
AResult := CBalance;
Result := False;
if not Assigned(ANode) then
exit;
if Assigned(ANode^.Children[CRight]) then
begin
if not DeleteFindHighest(ATarget, ANode^.Children[CRight], AResult) then
begin
Result := False;
exit;
end;
if AResult = CBalance then
AResult := DeleteRightShrunk(ANode);
Result := True;
exit; exit;
end; end;
pNode := Root; pSwap := ANode;
while Assigned(pNode) do CopyNodeData(ANode, ATarget);
ANode := ANode^.Children[CLeft];
FreeNode(pSwap);
Result := True;
end;
function TX2UtCustomBTree.DeleteFindLowest;
var
pSwap: PX2UtBTreeNode;
begin
AResult := CBalance;
Result := False;
if not Assigned(ANode) then
exit;
if Assigned(ANode^.Children[CLeft]) then
begin begin
if AIndex = pNode^.Index then if not DeleteFindLowest(ATarget, ANode^.Children[CLeft], AResult) then
begin begin
Result := pNode; Result := False;
break; exit;
end else if AIndex < pNode^.Index then
begin
if Assigned(pNode^.Left) then
pNode := pNode^.Left
else
begin
if ACanCreate then
begin
InitNode(pNode^.Left);
Result := pNode^.Left;
Result^.Index := AIndex;
Result^.Parent := pNode;
end;
break;
end;
end else
begin
if Assigned(pNode^.Right) then
pNode := pNode^.Right
else
begin
if ACanCreate then
begin
InitNode(pNode^.Right);
Result := pNode^.Right;
Result^.Index := AIndex;
Result^.Parent := pNode;
end;
break;
end;
end;
end;
if ASetCursor and Assigned(Result) then
begin
// Trace parents
Parent.Clear();
pNode := Result^.Parent;
while Assigned(pNode) do
begin
Parent.Push(pNode);
pNode := pNode^.Parent;
end; end;
// Parents are now in reverse order if AResult = CBalance then
Parent.Reverse(); AResult := DeleteLeftShrunk(ANode);
Result := True;
exit;
end; end;
pSwap := ANode;
CopyNodeData(ANode, ATarget);
ANode := ANode^.Children[CRight];
FreeNode(pSwap);
Result := True;
end;
function TX2UtCustomBTree.InternalDeleteNode;
var
iResult: Integer;
begin
if AIndex < ARoot^.Index then
begin
// Continue on the left side
iResult := InternalDeleteNode(ARoot^.Children[CLeft], AIndex);
if iResult = CBalance then
begin
Result := DeleteLeftShrunk(ARoot);
exit;
end;
Result := iResult;
exit;
end;
if AIndex > ARoot^.Index then
begin
// Continue on the right side
iResult := InternalDeleteNode(ARoot^.Children[CRight], AIndex);
if iResult = CBalance then
begin
Result := DeleteRightShrunk(ARoot);
exit;
end;
Result := iResult;
exit;
end;
if Assigned(ARoot^.Children[CLeft]) then
if DeleteFindHighest(ARoot, ARoot^.Children[CLeft], iResult) then
begin
if iResult = CBalance then
iResult := DeleteLeftShrunk(ARoot);
Result := iResult;
exit;
end;
if Assigned(ARoot^.Children[CRight]) then
if DeleteFindLowest(ARoot, ARoot^.Children[CRight], iResult) then
begin
if iResult = CBalance then
iResult := DeleteRightShrunk(ARoot);
Result := iResult;
exit;
end;
FreeNode(ARoot);
Result := CBalance;
end;
procedure TX2UtCustomBTree.DeleteNode;
begin
if not Assigned(FRoot) then
exit;
InternalDeleteNode(FRoot, AIndex);
end; end;
@ -388,45 +835,43 @@ begin
Assert(DataSize > 0, RSInvalidDataSize); Assert(DataSize > 0, RSInvalidDataSize);
GetMem(ANode, TotalSize); GetMem(ANode, TotalSize);
FillChar(ANode^, TotalSize, #0); FillChar(ANode^, TotalSize, #0);
Inc(FCount);
ClearCursor();
end; end;
procedure TX2UtCustomBTree.FreeNode; procedure TX2UtCustomBTree.FreeNode;
begin begin
if Assigned(ANode^.Left) then
FreeNode(ANode^.Left);
if Assigned(ANode^.Right) then
FreeNode(ANode^.Right);
if Assigned(ANode^.Parent) then
if ANode^.Parent^.Left = ANode then
ANode^.Parent^.Left := nil
else if ANode^.Parent^.Right = ANode then
ANode^.Parent^.Right := nil
else
Assert(False, RSOrphanNode);
FreeMem(ANode, TotalSize); FreeMem(ANode, TotalSize);
ClearCursor();
ANode := nil; ANode := nil;
Dec(FCount);
ClearCursor();
end; end;
procedure TX2UtCustomBTree.Clear; procedure TX2UtCustomBTree.Clear;
procedure ClearNode(var ANode: PX2UtBTreeNode);
begin
if Assigned(ANode^.Children[CLeft]) then
ClearNode(ANode^.Children[CLeft]);
if Assigned(ANode^.Children[CRight]) then
ClearNode(ANode^.Children[CRight]);
FreeNode(ANode);
end;
begin begin
if Assigned(FRoot) then if Assigned(FRoot) then
FreeNode(FRoot); ClearNode(FRoot);
FRoot := nil;
end; end;
procedure TX2UtCustomBTree.Delete; procedure TX2UtCustomBTree.Delete;
var
pItem: PX2UtBTreeNode;
begin begin
pItem := LookupNode(AIndex); DeleteNode(AIndex);
if Assigned(pItem) then
FreeNode(pItem);
end; end;
function TX2UtCustomBTree.Exists; function TX2UtCustomBTree.Exists;
@ -475,39 +920,40 @@ begin
if not IsReset then if not IsReset then
begin begin
if Assigned(Cursor^.Left) then if Assigned(Cursor^.Children[CLeft]) then
begin begin
// Valid left path, follow it // Valid left path, follow it
Parent.Push(Cursor); Parents.Push(Cursor);
Cursor := Cursor^.Left; Cursor := Cursor^.Children[CLeft];
Result := True; Result := True;
end else if Assigned(Cursor^.Right) then end else if Assigned(Cursor^.Children[CRight]) then
begin begin
// Valid right path, follow it // Valid right path, follow it
Parent.Push(Cursor); Parents.Push(Cursor);
Cursor := Cursor^.Right; Cursor := Cursor^.Children[CRight];
Result := True; Result := True;
end else end else
begin begin
// Neither is valid, traverse back up the parent stack until // Neither is valid, traverse back up the parent stack until
// a node if found with a sibling // a node if found with a sibling
pCurrent := Cursor; pCurrent := Cursor;
pParent := Parent.Pop(); pParent := Parents.Pop();
ClearCursor(); ClearCursor();
while Assigned(pParent) do while Assigned(pParent) do
begin begin
if Assigned(pParent^.Right) and (pParent^.Right <> pCurrent) then if Assigned(pParent^.Children[CRight]) and
(pParent^.Children[CRight] <> pCurrent) then
begin begin
// Parent has a sibling, follow it // Parent has a sibling, follow it
Parent.Push(pParent); Parents.Push(pParent);
Cursor := pParent^.Right; Cursor := pParent^.Children[CRight];
Result := True; Result := True;
break; break;
end; end;
pCurrent := pParent; pCurrent := pParent;
pParent := Parent.Pop(); pParent := Parents.Pop();
end; end;
end; end;
end else end else

View File

@ -177,8 +177,6 @@ var
pValue: PChar; pValue: PChar;
begin begin
Result := 0;
iA := $9e3779b9; iA := $9e3779b9;
iB := iA; iB := iA;
iC := iA; iC := iA;
@ -377,19 +375,10 @@ end;
function TX2UtCustomHash.GetCurrentKey; function TX2UtCustomHash.GetCurrentKey;
var
pKey: PString;
begin begin
Result := ''; Result := '';
if ValidCursor(True) then if ValidCursor(True) then
begin
Result := HashCursor^.Key; Result := HashCursor^.Key;
{
pKey := GetNodeInternal(Cursor);
Result := pKey^;
}
end;
end; end;
@ -537,9 +526,6 @@ end;
function TX2UtStringHash.GetCurrentValue; function TX2UtStringHash.GetCurrentValue;
var
pData: PString;
begin begin
if ValidCursor() then if ValidCursor() then
Result := PString(GetItemData(HashCursor))^; Result := PString(GetItemData(HashCursor))^;