3286 lines
81 KiB
ObjectPascal
3286 lines
81 KiB
ObjectPascal
{**************************************************************************************************}
|
|
{ }
|
|
{ Project JEDI Code Library (JCL) }
|
|
{ }
|
|
{ The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
|
|
{ you may not use this file except in compliance with the License. You may obtain a copy of the }
|
|
{ License at http://www.mozilla.org/MPL/ }
|
|
{ }
|
|
{ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF }
|
|
{ ANY KIND, either express or implied. See the License for the specific language governing rights }
|
|
{ and limitations under the License. }
|
|
{ }
|
|
{ The Original Code is BinaryTree.pas. }
|
|
{ }
|
|
{ The Initial Developer of the Original Code is Jean-Philippe BEMPEL aka RDM. Portions created by }
|
|
{ Jean-Philippe BEMPEL are Copyright (C) Jean-Philippe BEMPEL (rdm_30 att yahoo dott com) }
|
|
{ All rights reserved. }
|
|
{ }
|
|
{**************************************************************************************************}
|
|
{ }
|
|
{ The Delphi Container Library }
|
|
{ }
|
|
{**************************************************************************************************}
|
|
|
|
// Last modified: $Date: 2005/05/05 20:08:42 $
|
|
// For history see end of file
|
|
|
|
unit JclBinaryTrees;
|
|
|
|
{$I jcl.inc}
|
|
|
|
{.DEFINE RECURSIVE}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes,
|
|
JclBase, JclAbstractContainers, JclAlgorithms, JclContainerIntf;
|
|
|
|
type
|
|
TJclTreeColor = (tcBlack, tcRed);
|
|
|
|
{$IFDEF CLR}
|
|
TJclIntfBinaryNode = class;
|
|
PJclIntfBinaryNode = TJclIntfBinaryNode;
|
|
TJclIntfBinaryNode = class
|
|
{$ELSE}
|
|
PJclIntfBinaryNode = ^TJclIntfBinaryNode;
|
|
TJclIntfBinaryNode = record
|
|
{$ENDIF CLR}
|
|
Obj: IInterface;
|
|
Left: PJclIntfBinaryNode;
|
|
Right: PJclIntfBinaryNode;
|
|
Parent: PJclIntfBinaryNode;
|
|
Color: TJclTreeColor;
|
|
end;
|
|
|
|
{$IFDEF CLR}
|
|
TJclStrBinaryNode = class;
|
|
PJclStrBinaryNode = TJclStrBinaryNode;
|
|
TJclStrBinaryNode = class
|
|
{$ELSE}
|
|
PJclStrBinaryNode = ^TJclStrBinaryNode;
|
|
TJclStrBinaryNode = record
|
|
{$ENDIF CLR}
|
|
Str: string;
|
|
Left: PJclStrBinaryNode;
|
|
Right: PJclStrBinaryNode;
|
|
Parent: PJclStrBinaryNode;
|
|
Color: TJclTreeColor;
|
|
end;
|
|
|
|
{$IFDEF CLR}
|
|
TJclBinaryNode = class;
|
|
PJclBinaryNode = TJclBinaryNode;
|
|
TJclBinaryNode = class
|
|
{$ELSE}
|
|
PJclBinaryNode = ^TJclBinaryNode;
|
|
TJclBinaryNode = record
|
|
{$ENDIF CLR}
|
|
Obj: TObject;
|
|
Left: PJclBinaryNode;
|
|
Right: PJclBinaryNode;
|
|
Parent: PJclBinaryNode;
|
|
Color: TJclTreeColor;
|
|
end;
|
|
|
|
TJclIntfBinaryTree = class(TJclAbstractContainer, IJclIntfCollection,
|
|
IJclIntfTree, IJclIntfCloneable)
|
|
private
|
|
FComparator: TIntfCompare;
|
|
FCount: Integer;
|
|
FRoot: PJclIntfBinaryNode;
|
|
FTraverseOrder: TJclTraverseOrder;
|
|
procedure RotateLeft(Node: PJclIntfBinaryNode);
|
|
procedure RotateRight(Node: PJclIntfBinaryNode);
|
|
protected
|
|
{ IJclIntfCollection }
|
|
function Add(AInterface: IInterface): Boolean;
|
|
function AddAll(ACollection: IJclIntfCollection): Boolean;
|
|
procedure Clear;
|
|
function Contains(AInterface: IInterface): Boolean;
|
|
function ContainsAll(ACollection: IJclIntfCollection): Boolean;
|
|
function Equals(ACollection: IJclIntfCollection): Boolean;
|
|
function First: IJclIntfIterator;
|
|
function IsEmpty: Boolean;
|
|
function Last: IJclIntfIterator;
|
|
function Remove(AInterface: IInterface): Boolean;
|
|
function RemoveAll(ACollection: IJclIntfCollection): Boolean;
|
|
function RetainAll(ACollection: IJclIntfCollection): Boolean;
|
|
function Size: Integer;
|
|
{ IJclIntfTree }
|
|
function GetTraverseOrder: TJclTraverseOrder;
|
|
procedure SetTraverseOrder(Value: TJclTraverseOrder);
|
|
{ IJclIntfCloneable }
|
|
function Clone: IInterface;
|
|
public
|
|
constructor Create(AComparator: TIntfCompare = nil);
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
{
|
|
TJclStrBinaryTree = class(TJclAbstractContainer, IJclStrCollection,
|
|
IJclStrTree, IJclCloneable)
|
|
}
|
|
TJclStrBinaryTree = class(TJclStrCollection, IJclStrTree, IJclCloneable)
|
|
private
|
|
FComparator: TStrCompare;
|
|
FCount: Integer;
|
|
FRoot: PJclStrBinaryNode;
|
|
FTraverseOrder: TJclTraverseOrder;
|
|
procedure RotateLeft(Node: PJclStrBinaryNode);
|
|
procedure RotateRight(Node: PJclStrBinaryNode);
|
|
protected
|
|
{ IJclStrCollection }
|
|
function Add(const AString: string): Boolean; override;
|
|
function AddAll(ACollection: IJclStrCollection): Boolean; override;
|
|
procedure Clear; override;
|
|
function Contains(const AString: string): Boolean; override;
|
|
function ContainsAll(ACollection: IJclStrCollection): Boolean; override;
|
|
function Equals(ACollection: IJclStrCollection): Boolean; override;
|
|
function First: IJclStrIterator; override;
|
|
function IsEmpty: Boolean; override;
|
|
function Last: IJclStrIterator; override;
|
|
function Remove(const AString: string): Boolean; override;
|
|
function RemoveAll(ACollection: IJclStrCollection): Boolean; override;
|
|
function RetainAll(ACollection: IJclStrCollection): Boolean; override;
|
|
function Size: Integer; override;
|
|
{ IJclStrTree }
|
|
function GetTraverseOrder: TJclTraverseOrder;
|
|
procedure SetTraverseOrder(Value: TJclTraverseOrder);
|
|
{ IJclCloneable }
|
|
function Clone: TObject;
|
|
public
|
|
constructor Create(AComparator: TStrCompare = nil);
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
TJclBinaryTree = class(TJclAbstractContainer, IJclCollection, IJclTree,
|
|
IJclCloneable)
|
|
private
|
|
FComparator: TCompare;
|
|
FCount: Integer;
|
|
FRoot: PJclBinaryNode;
|
|
FTraverseOrder: TJclTraverseOrder;
|
|
procedure RotateLeft(Node: PJclBinaryNode);
|
|
procedure RotateRight(Node: PJclBinaryNode);
|
|
protected
|
|
{ IJclCollection }
|
|
function Add(AObject: TObject): Boolean;
|
|
function AddAll(ACollection: IJclCollection): Boolean;
|
|
procedure Clear;
|
|
function Contains(AObject: TObject): Boolean;
|
|
function ContainsAll(ACollection: IJclCollection): Boolean;
|
|
function Equals(ACollection: IJclCollection): Boolean;
|
|
function First: IJclIterator;
|
|
function IsEmpty: Boolean;
|
|
function Last: IJclIterator;
|
|
function Remove(AObject: TObject): Boolean;
|
|
function RemoveAll(ACollection: IJclCollection): Boolean;
|
|
function RetainAll(ACollection: IJclCollection): Boolean;
|
|
function Size: Integer;
|
|
{ IJclTree }
|
|
function GetTraverseOrder: TJclTraverseOrder;
|
|
procedure SetTraverseOrder(Value: TJclTraverseOrder);
|
|
{ IJclCloneable }
|
|
function Clone: TObject;
|
|
public
|
|
constructor Create(AComparator: TCompare = nil);
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
SysUtils,
|
|
JclResources;
|
|
|
|
//=== { TIntfItr } ===========================================================
|
|
|
|
type
|
|
TIntfItr = class(TJclAbstractContainer, IJclIntfIterator)
|
|
private
|
|
FCursor: PJclIntfBinaryNode;
|
|
FOwnList: TJclIntfBinaryTree;
|
|
FLastRet: PJclIntfBinaryNode;
|
|
protected
|
|
{ IJclIntfIterator }
|
|
procedure Add(AInterface: IInterface);
|
|
function GetObject: IInterface;
|
|
function HasNext: Boolean;
|
|
function HasPrevious: Boolean;
|
|
function Next: IInterface; virtual;
|
|
function NextIndex: Integer;
|
|
function Previous: IInterface; virtual;
|
|
function PreviousIndex: Integer;
|
|
procedure Remove;
|
|
procedure SetObject(AInterface: IInterface);
|
|
public
|
|
constructor Create(OwnList: TJclIntfBinaryTree; Start: PJclIntfBinaryNode);
|
|
{$IFNDEF CLR}
|
|
destructor Destroy; override;
|
|
{$ENDIF ~CLR}
|
|
end;
|
|
|
|
constructor TIntfItr.Create(OwnList: TJclIntfBinaryTree; Start: PJclIntfBinaryNode);
|
|
begin
|
|
inherited Create;
|
|
FCursor := Start;
|
|
FOwnList := OwnList;
|
|
{$IFNDEF CLR}
|
|
FOwnList._AddRef; // Add a ref because FOwnList is not an interface !
|
|
{$ENDIF ~CLR}
|
|
end;
|
|
|
|
{$IFNDEF CLR}
|
|
destructor TIntfItr.Destroy;
|
|
begin
|
|
FOwnList._Release;
|
|
inherited Destroy;
|
|
end;
|
|
{$ENDIF ~CLR}
|
|
|
|
procedure TIntfItr.Add(AInterface: IInterface);
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
FOwnList.Add(AInterface);
|
|
end;
|
|
|
|
function TIntfItr.GetObject: IInterface;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := FCursor.Obj;
|
|
end;
|
|
|
|
function TIntfItr.HasNext: Boolean;
|
|
begin
|
|
Result := FCursor <> nil;
|
|
end;
|
|
|
|
function TIntfItr.HasPrevious: Boolean;
|
|
begin
|
|
Result := FCursor <> nil;
|
|
end;
|
|
|
|
function TIntfItr.Next: IInterface;
|
|
begin
|
|
end;
|
|
|
|
function TIntfItr.NextIndex: Integer;
|
|
begin
|
|
// No index
|
|
{$IFDEF CLR}
|
|
raise EJclOperationNotSupportedError.Create(RsEOperationNotSupported);
|
|
{$ELSE}
|
|
raise EJclOperationNotSupportedError.CreateRes(@RsEOperationNotSupported);
|
|
{$ENDIF CLR}
|
|
end;
|
|
|
|
function TIntfItr.Previous: IInterface;
|
|
begin
|
|
end;
|
|
|
|
function TIntfItr.PreviousIndex: Integer;
|
|
begin
|
|
// No index
|
|
{$IFDEF CLR}
|
|
raise EJclOperationNotSupportedError.Create(RsEOperationNotSupported);
|
|
{$ELSE}
|
|
raise EJclOperationNotSupportedError.CreateRes(@RsEOperationNotSupported);
|
|
{$ENDIF CLR}
|
|
end;
|
|
|
|
procedure TIntfItr.Remove;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
FOwnList.Remove(Next);
|
|
end;
|
|
|
|
procedure TIntfItr.SetObject(AInterface: IInterface);
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
FCursor.Obj := AInterface;
|
|
end;
|
|
|
|
//=== { TPreOrderIntfItr } ===================================================
|
|
|
|
type
|
|
TPreOrderIntfItr = class(TIntfItr, IJclIntfIterator)
|
|
protected
|
|
{ IJclIntfIterator }
|
|
function Next: IInterface; override;
|
|
function Previous: IInterface; override;
|
|
end;
|
|
|
|
function TPreOrderIntfItr.Next: IInterface;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := FCursor.Obj;
|
|
FLastRet := FCursor;
|
|
if FCursor.Left <> nil then
|
|
FCursor := FCursor.Left
|
|
else
|
|
if FCursor.Right <> nil then
|
|
FCursor := FCursor.Right
|
|
else
|
|
begin
|
|
FCursor := FCursor.Parent;
|
|
while (FCursor <> nil) and (FCursor.Left <> FLastRet) do // come from Right
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
while (FCursor <> nil) and (FCursor.Right = nil) do
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
if FCursor <> nil then // not root
|
|
FCursor := FCursor.Right;
|
|
end;
|
|
end;
|
|
|
|
function TPreOrderIntfItr.Previous: IInterface;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := FCursor.Obj;
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Parent;
|
|
if (FCursor <> nil) and (FCursor.Left <> FLastRet) then // come from Right
|
|
if FCursor.Left <> nil then
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Left;
|
|
while FCursor.Right <> nil do
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Right;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TInOrderIntfItr } ====================================================
|
|
|
|
type
|
|
TInOrderIntfItr = class(TIntfItr, IJclIntfIterator)
|
|
protected
|
|
{ IJclIntfIterator }
|
|
function Next: IInterface; override;
|
|
function Previous: IInterface; override;
|
|
end;
|
|
|
|
function TInOrderIntfItr.Next: IInterface;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
if FCursor.Left <> FLastRet then
|
|
while FCursor.Left <> nil do
|
|
FCursor := FCursor.Left;
|
|
Result := FCursor.Obj;
|
|
FLastRet := FCursor;
|
|
if FCursor.Right <> nil then
|
|
FCursor := FCursor.Right
|
|
else
|
|
begin
|
|
FCursor := FCursor.Parent;
|
|
while (FCursor <> nil) and (FCursor.Right = FLastRet) do
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TInOrderIntfItr.Previous: IInterface;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := FCursor.Obj;
|
|
FLastRet := FCursor;
|
|
if FCursor.Left <> nil then
|
|
begin
|
|
FCursor := FCursor.Left;
|
|
while FCursor.Right <> nil do
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Right;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
FCursor := FCursor.Parent;
|
|
while (FCursor <> nil) and (FCursor.Right <> FLastRet) do // Come from Left
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TPostOrderIntfItr } ==================================================
|
|
|
|
type
|
|
TPostOrderIntfItr = class(TIntfItr, IJclIntfIterator)
|
|
protected
|
|
{ IJclIntfIterator }
|
|
function Next: IInterface; override;
|
|
function Previous: IInterface; override;
|
|
end;
|
|
|
|
function TPostOrderIntfItr.Next: IInterface;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
if (FCursor.Left <> FLastRet) and (FCursor.Right <> FLastRet) then
|
|
while FCursor.Left <> nil do
|
|
FCursor := FCursor.Left;
|
|
if (FCursor.Right <> nil) and (FCursor.Right <> FLastRet) then
|
|
begin
|
|
FCursor := FCursor.Right;
|
|
while FCursor.Left <> nil do
|
|
FCursor := FCursor.Left;
|
|
if FCursor.Right <> nil then // particular worst case
|
|
FCursor := FCursor.Right;
|
|
end;
|
|
Result := FCursor.Obj;
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
|
|
function TPostOrderIntfItr.Previous: IInterface;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := FCursor.Obj;
|
|
FLastRet := FCursor;
|
|
if (FCursor.Right <> nil) and (FCursor.Right <> FLastRet) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
begin
|
|
FCursor := FCursor.Parent;
|
|
while (FCursor <> nil) and ((FCursor.Left = nil) or (FCursor.Left = FLastRet)) do
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
if FCursor <> nil then // not root
|
|
FCursor := FCursor.Left;
|
|
end;
|
|
end;
|
|
|
|
//=== { TStrItr } ============================================================
|
|
|
|
type
|
|
TStrItr = class(TJclAbstractContainer, IJclStrIterator)
|
|
protected
|
|
FCursor: PJclStrBinaryNode;
|
|
FOwnList: TJclStrBinaryTree;
|
|
FLastRet: PJclStrBinaryNode;
|
|
{ IJclStrIterator }
|
|
procedure Add(const AString: string);
|
|
function GetString: string;
|
|
function HasNext: Boolean;
|
|
function HasPrevious: Boolean;
|
|
function Next: string; virtual;
|
|
function NextIndex: Integer;
|
|
function Previous: string; virtual;
|
|
function PreviousIndex: Integer;
|
|
procedure Remove;
|
|
procedure SetString(const AString: string);
|
|
public
|
|
constructor Create(OwnList: TJclStrBinaryTree; Start: PJclStrBinaryNode);
|
|
{$IFNDEF CLR}
|
|
destructor Destroy; override;
|
|
{$ENDIF ~CLR}
|
|
end;
|
|
|
|
constructor TStrItr.Create(OwnList: TJclStrBinaryTree; Start: PJclStrBinaryNode);
|
|
begin
|
|
inherited Create;
|
|
FCursor := Start;
|
|
FOwnList := OwnList;
|
|
{$IFNDEF CLR}
|
|
FOwnList._AddRef; // Add a ref because FOwnList is not an interface !
|
|
{$ENDIF ~CLR}
|
|
end;
|
|
|
|
{$IFNDEF CLR}
|
|
destructor TStrItr.Destroy;
|
|
begin
|
|
FOwnList._Release;
|
|
inherited Destroy;
|
|
end;
|
|
{$ENDIF ~CLR}
|
|
|
|
procedure TStrItr.Add(const AString: string);
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
FOwnList.Add(AString);
|
|
end;
|
|
|
|
function TStrItr.GetString: string;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := FCursor.Str;
|
|
end;
|
|
|
|
function TStrItr.HasNext: Boolean;
|
|
begin
|
|
Result := FCursor <> nil;
|
|
end;
|
|
|
|
function TStrItr.HasPrevious: Boolean;
|
|
begin
|
|
Result := FCursor <> nil;
|
|
end;
|
|
|
|
function TStrItr.Next: string;
|
|
begin
|
|
end;
|
|
|
|
function TStrItr.NextIndex: Integer;
|
|
begin
|
|
// No index
|
|
{$IFDEF CLR}
|
|
raise EJclOperationNotSupportedError.Create(RsEOperationNotSupported);
|
|
{$ELSE}
|
|
raise EJclOperationNotSupportedError.CreateRes(@RsEOperationNotSupported);
|
|
{$ENDIF CLR}
|
|
end;
|
|
|
|
function TStrItr.Previous: string;
|
|
begin
|
|
end;
|
|
|
|
function TStrItr.PreviousIndex: Integer;
|
|
begin
|
|
// No index
|
|
{$IFDEF CLR}
|
|
raise EJclOperationNotSupportedError.Create(RsEOperationNotSupported);
|
|
{$ELSE}
|
|
raise EJclOperationNotSupportedError.CreateRes(@RsEOperationNotSupported);
|
|
{$ENDIF CLR}
|
|
end;
|
|
|
|
procedure TStrItr.Remove;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
FOwnList.Remove(Next);
|
|
end;
|
|
|
|
procedure TStrItr.SetString(const AString: string);
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
FCursor.Str := AString;
|
|
end;
|
|
|
|
//=== { TPreOrderStrItr } ====================================================
|
|
|
|
type
|
|
TPreOrderStrItr = class(TStrItr, IJclStrIterator)
|
|
protected
|
|
{ IJclStrIterator }
|
|
function Next: string; override;
|
|
function Previous: string; override;
|
|
end;
|
|
|
|
function TPreOrderStrItr.Next: string;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := FCursor.Str;
|
|
FLastRet := FCursor;
|
|
if FCursor.Left <> nil then
|
|
FCursor := FCursor.Left
|
|
else
|
|
if FCursor.Right <> nil then
|
|
FCursor := FCursor.Right
|
|
else
|
|
begin
|
|
FCursor := FCursor.Parent;
|
|
while (FCursor <> nil) and (FCursor.Left <> FLastRet) do // come from Right
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
while (FCursor <> nil) and (FCursor.Right = nil) do
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
if FCursor <> nil then // not root
|
|
FCursor := FCursor.Right;
|
|
end;
|
|
end;
|
|
|
|
function TPreOrderStrItr.Previous: string;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := FCursor.Str;
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Parent;
|
|
if (FCursor <> nil) and (FCursor.Left <> FLastRet) then // come from Right
|
|
if FCursor.Left <> nil then
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Left;
|
|
while FCursor.Right <> nil do
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Right;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TInOrderStrItr } =====================================================
|
|
|
|
type
|
|
TInOrderStrItr = class(TStrItr, IJclStrIterator)
|
|
protected
|
|
{ IJclStrIterator }
|
|
function Next: string; override;
|
|
function Previous: string; override;
|
|
end;
|
|
|
|
function TInOrderStrItr.Next: string;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
if FCursor.Left <> FLastRet then
|
|
while FCursor.Left <> nil do
|
|
FCursor := FCursor.Left;
|
|
Result := FCursor.Str;
|
|
FLastRet := FCursor;
|
|
if FCursor.Right <> nil then
|
|
FCursor := FCursor.Right
|
|
else
|
|
begin
|
|
FCursor := FCursor.Parent;
|
|
while (FCursor <> nil) and (FCursor.Right = FLastRet) do
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TInOrderStrItr.Previous: string;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := FCursor.Str;
|
|
FLastRet := FCursor;
|
|
if FCursor.Left <> nil then
|
|
begin
|
|
FCursor := FCursor.Left;
|
|
while FCursor.Right <> nil do
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Right;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
FCursor := FCursor.Parent;
|
|
while (FCursor <> nil) and (FCursor.Right <> FLastRet) do // Come from Left
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TPostOrderStrItr } ===================================================
|
|
|
|
type
|
|
TPostOrderStrItr = class(TStrItr, IJclStrIterator)
|
|
protected
|
|
{ IJclStrIterator }
|
|
function Next: string; override;
|
|
function Previous: string; override;
|
|
end;
|
|
|
|
function TPostOrderStrItr.Next: string;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
if (FCursor.Left <> FLastRet) and (FCursor.Right <> FLastRet) then
|
|
while FCursor.Left <> nil do
|
|
FCursor := FCursor.Left;
|
|
if (FCursor.Right <> nil) and (FCursor.Right <> FLastRet) then
|
|
begin
|
|
FCursor := FCursor.Right;
|
|
while FCursor.Left <> nil do
|
|
FCursor := FCursor.Left;
|
|
if FCursor.Right <> nil then // particular worst case
|
|
FCursor := FCursor.Right;
|
|
end;
|
|
Result := FCursor.Str;
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
|
|
function TPostOrderStrItr.Previous: string;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := FCursor.Str;
|
|
FLastRet := FCursor;
|
|
if (FCursor.Right <> nil) and (FCursor.Right <> FLastRet) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
begin
|
|
FCursor := FCursor.Parent;
|
|
while (FCursor <> nil) and ((FCursor.Left = nil) or (FCursor.Left = FLastRet)) do
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
if FCursor <> nil then // not root
|
|
FCursor := FCursor.Left;
|
|
end;
|
|
end;
|
|
|
|
//=== { TItr } ===============================================================
|
|
|
|
type
|
|
TItr = class(TJclAbstractContainer, IJclIterator)
|
|
protected
|
|
FCursor: PJclBinaryNode;
|
|
FOwnList: TJclBinaryTree;
|
|
FLastRet: PJclBinaryNode;
|
|
{ IJclIntfIterator }
|
|
procedure Add(AObject: TObject);
|
|
function GetObject: TObject;
|
|
function HasNext: Boolean;
|
|
function HasPrevious: Boolean;
|
|
function Next: TObject; virtual;
|
|
function NextIndex: Integer;
|
|
function Previous: TObject; virtual;
|
|
function PreviousIndex: Integer;
|
|
procedure Remove;
|
|
procedure SetObject(AObject: TObject);
|
|
public
|
|
constructor Create(OwnList: TJclBinaryTree; Start: PJclBinaryNode);
|
|
{$IFNDEF CLR}
|
|
destructor Destroy; override;
|
|
{$ENDIF ~CLR}
|
|
end;
|
|
|
|
constructor TItr.Create(OwnList: TJclBinaryTree; Start: PJclBinaryNode);
|
|
begin
|
|
inherited Create;
|
|
FCursor := Start;
|
|
FOwnList := OwnList;
|
|
{$IFNDEF CLR}
|
|
FOwnList._AddRef; // Add a ref because FOwnList is not an interface !
|
|
{$ENDIF ~CLR}
|
|
end;
|
|
|
|
{$IFNDEF CLR}
|
|
destructor TItr.Destroy;
|
|
begin
|
|
FOwnList._Release;
|
|
inherited Destroy;
|
|
end;
|
|
{$ENDIF ~CLR}
|
|
|
|
procedure TItr.Add(AObject: TObject);
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
FOwnList.Add(AObject);
|
|
end;
|
|
|
|
function TItr.GetObject: TObject;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := FCursor.Obj;
|
|
end;
|
|
|
|
function TItr.HasNext: Boolean;
|
|
begin
|
|
Result := FCursor <> nil;
|
|
end;
|
|
|
|
function TItr.HasPrevious: Boolean;
|
|
begin
|
|
Result := FCursor <> nil;
|
|
end;
|
|
|
|
function TItr.Next: TObject;
|
|
begin
|
|
Result := nil; // overriden in derived class
|
|
end;
|
|
|
|
function TItr.NextIndex: Integer;
|
|
begin
|
|
// No index
|
|
{$IFDEF CLR}
|
|
raise EJclOperationNotSupportedError.Create(RsEOperationNotSupported);
|
|
{$ELSE}
|
|
raise EJclOperationNotSupportedError.CreateRes(@RsEOperationNotSupported);
|
|
{$ENDIF CLR}
|
|
end;
|
|
|
|
function TItr.Previous: TObject;
|
|
begin
|
|
Result := nil; // overriden in derived class
|
|
end;
|
|
|
|
function TItr.PreviousIndex: Integer;
|
|
begin
|
|
// No index
|
|
{$IFDEF CLR}
|
|
raise EJclOperationNotSupportedError.Create(RsEOperationNotSupported);
|
|
{$ELSE}
|
|
raise EJclOperationNotSupportedError.CreateRes(@RsEOperationNotSupported);
|
|
{$ENDIF CLR}
|
|
end;
|
|
|
|
procedure TItr.Remove;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
FOwnList.Remove(Next);
|
|
end;
|
|
|
|
procedure TItr.SetObject(AObject: TObject);
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
FCursor.Obj := AObject;
|
|
end;
|
|
|
|
//=== { TPreOrderItr } =======================================================
|
|
|
|
type
|
|
TPreOrderItr = class(TItr, IJclIterator)
|
|
protected
|
|
{ IJclIterator }
|
|
function Next: TObject; override;
|
|
function Previous: TObject; override;
|
|
end;
|
|
|
|
function TPreOrderItr.Next: TObject;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := FCursor.Obj;
|
|
FLastRet := FCursor;
|
|
if FCursor.Left <> nil then
|
|
FCursor := FCursor.Left
|
|
else
|
|
if FCursor.Right <> nil then
|
|
FCursor := FCursor.Right
|
|
else
|
|
begin
|
|
FCursor := FCursor.Parent;
|
|
while (FCursor <> nil) and (FCursor.Left <> FLastRet) do // come from Right
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
while (FCursor <> nil) and (FCursor.Right = nil) do
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
if FCursor <> nil then // not root
|
|
FCursor := FCursor.Right;
|
|
end;
|
|
end;
|
|
|
|
function TPreOrderItr.Previous: TObject;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := FCursor.Obj;
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Parent;
|
|
if (FCursor <> nil) and (FCursor.Left <> FLastRet) then // come from Right
|
|
if FCursor.Left <> nil then
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Left;
|
|
while FCursor.Right <> nil do
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Right;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TInOrderItr } ========================================================
|
|
|
|
type
|
|
TInOrderItr = class(TItr, IJclIterator)
|
|
protected
|
|
{ IJclIterator }
|
|
function Next: TObject; override;
|
|
function Previous: TObject; override;
|
|
end;
|
|
|
|
function TInOrderItr.Next: TObject;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
if FCursor.Left <> FLastRet then
|
|
while FCursor.Left <> nil do
|
|
FCursor := FCursor.Left;
|
|
Result := FCursor.Obj;
|
|
FLastRet := FCursor;
|
|
if FCursor.Right <> nil then
|
|
FCursor := FCursor.Right
|
|
else
|
|
begin
|
|
FCursor := FCursor.Parent;
|
|
while (FCursor <> nil) and (FCursor.Right = FLastRet) do
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TInOrderItr.Previous: TObject;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := FCursor.Obj;
|
|
FLastRet := FCursor;
|
|
if FCursor.Left <> nil then
|
|
begin
|
|
FCursor := FCursor.Left;
|
|
while FCursor.Right <> nil do
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Right;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
FCursor := FCursor.Parent;
|
|
while (FCursor <> nil) and (FCursor.Right <> FLastRet) do // Come from Left
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TPostOrderItr } ======================================================
|
|
|
|
type
|
|
TPostOrderItr = class(TItr, IJclIterator)
|
|
protected
|
|
{ IJclIterator }
|
|
function Next: TObject; override;
|
|
function Previous: TObject; override;
|
|
end;
|
|
|
|
function TPostOrderItr.Next: TObject;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
if (FCursor.Left <> FLastRet) and (FCursor.Right <> FLastRet) then
|
|
while FCursor.Left <> nil do
|
|
FCursor := FCursor.Left;
|
|
if (FCursor.Right <> nil) and (FCursor.Right <> FLastRet) then
|
|
begin
|
|
FCursor := FCursor.Right;
|
|
while FCursor.Left <> nil do
|
|
FCursor := FCursor.Left;
|
|
if FCursor.Right <> nil then // particular worst case
|
|
FCursor := FCursor.Right;
|
|
end;
|
|
Result := FCursor.Obj;
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
|
|
function TPostOrderItr.Previous: TObject;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := FCursor.Obj;
|
|
FLastRet := FCursor;
|
|
if (FCursor.Right <> nil) and (FCursor.Right <> FLastRet) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
begin
|
|
FCursor := FCursor.Parent;
|
|
while (FCursor <> nil) and ((FCursor.Left = nil) or (FCursor.Left = FLastRet)) do
|
|
begin
|
|
FLastRet := FCursor;
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
if FCursor <> nil then // not root
|
|
FCursor := FCursor.Left;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclIntfBinaryTree } =================================================
|
|
|
|
constructor TJclIntfBinaryTree.Create(AComparator: TIntfCompare = nil);
|
|
begin
|
|
inherited Create;
|
|
if Assigned(AComparator) then
|
|
FComparator := AComparator
|
|
else
|
|
FComparator := @IntfSimpleCompare;
|
|
FTraverseOrder := toPreOrder;
|
|
end;
|
|
|
|
destructor TJclIntfBinaryTree.Destroy;
|
|
begin
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.Add(AInterface: IInterface): Boolean;
|
|
var
|
|
NewNode: PJclIntfBinaryNode;
|
|
Current, Save: PJclIntfBinaryNode;
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AInterface = nil then
|
|
Exit;
|
|
{$IFDEF CLR}
|
|
NewNode := TJclIntfBinaryNode.Create;
|
|
{$ELSE}
|
|
NewNode := AllocMem(SizeOf(TJclIntfBinaryNode));
|
|
{$ENDIF CLR}
|
|
NewNode.Obj := AInterface;
|
|
// Insert into right place
|
|
Save := nil;
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Save := Current;
|
|
if FComparator(NewNode.Obj, Current.Obj) < 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
NewNode.Parent := Save;
|
|
if Save = nil then
|
|
FRoot := NewNode
|
|
else
|
|
if FComparator(NewNode.Obj, Save.Obj) < 0 then
|
|
Save.Left := NewNode
|
|
else
|
|
Save.Right := NewNode;
|
|
// RB balanced
|
|
NewNode.Color := tcRed;
|
|
while (NewNode <> FRoot) and (NewNode.Parent.Color = tcRed) do
|
|
begin
|
|
if (NewNode.Parent.Parent <> nil) and (NewNode.Parent = NewNode.Parent.Parent.Left) then
|
|
begin
|
|
Current := NewNode.Parent.Parent.Right;
|
|
if Current.Color = tcRed then
|
|
begin
|
|
NewNode.Parent.Color := tcBlack;
|
|
Current.Color := tcBlack;
|
|
NewNode.Parent.Parent.Color := tcRed;
|
|
NewNode := NewNode.Parent.Parent;
|
|
end
|
|
else
|
|
begin
|
|
if NewNode = NewNode.Parent.Right then
|
|
begin
|
|
NewNode := NewNode.Parent;
|
|
RotateLeft(NewNode);
|
|
end;
|
|
NewNode.Parent.Color := tcBlack;
|
|
NewNode.Parent.Parent.Color := tcRed;
|
|
RotateRight(NewNode.Parent.Parent);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if NewNode.Parent.Parent = nil then
|
|
Current := nil
|
|
else
|
|
Current := NewNode.Parent.Parent.Left;
|
|
if (Current <> nil) and (Current.Color = tcRed) then
|
|
begin
|
|
NewNode.Parent.Color := tcBlack;
|
|
Current.Color := tcBlack;
|
|
NewNode.Parent.Parent.Color := tcRed;
|
|
NewNode := NewNode.Parent.Parent;
|
|
end
|
|
else
|
|
begin
|
|
if NewNode = NewNode.Parent.Left then
|
|
begin
|
|
NewNode := NewNode.Parent;
|
|
RotateRight(NewNode);
|
|
end;
|
|
NewNode.Parent.Color := tcBlack;
|
|
if NewNode.Parent.Parent <> nil then
|
|
NewNode.Parent.Parent.Color := tcRed;
|
|
RotateLeft(NewNode.Parent.Parent);
|
|
end;
|
|
end;
|
|
end;
|
|
FRoot.Color := tcBlack;
|
|
Inc(FCount);
|
|
Result := True;
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.AddAll(ACollection: IJclIntfCollection): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Add(It.Next) or Result;
|
|
end;
|
|
|
|
procedure TJclIntfBinaryTree.Clear;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
|
|
{$IFDEF RECURSIVE}
|
|
procedure FreeChild(Node: PJclIntfBinaryNode);
|
|
begin
|
|
if Node.Left <> nil then
|
|
FreeChild(Node.Left);
|
|
if Node.Right <> nil then
|
|
FreeChild(Node.Right);
|
|
Node.Obj := nil; // Force Release
|
|
FreeMem(Node);
|
|
end;
|
|
{$ELSE}
|
|
var
|
|
Current: PJclIntfBinaryNode;
|
|
Save: PJclIntfBinaryNode;
|
|
{$ENDIF RECURSIVE}
|
|
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
{$IFDEF RECURSIVE}
|
|
// recursive version
|
|
if FRoot <> nil then
|
|
begin
|
|
FreeChild(FRoot);
|
|
FRoot := nil;
|
|
end;
|
|
{$ELSE}
|
|
// iterative version
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
if Current.Right <> nil then
|
|
Current := Current.Right
|
|
else
|
|
begin
|
|
Current.Obj := nil; // Force Release
|
|
if Current.Parent = nil then // Root
|
|
begin
|
|
{$IFDEF CLR}
|
|
Current.Free;
|
|
{$ELSE}
|
|
FreeMem(Current);
|
|
{$ENDIF CLR}
|
|
Current := nil;
|
|
FRoot := nil;
|
|
end
|
|
else
|
|
begin
|
|
Save := Current;
|
|
Current := Current.Parent;
|
|
if Save = Current.Right then // True = from Right
|
|
begin
|
|
{$IFDEF CLR}
|
|
Save.Free;
|
|
{$ELSE}
|
|
FreeMem(Save);
|
|
{$ENDIF CLR}
|
|
Current.Right := nil;
|
|
end
|
|
else
|
|
begin
|
|
{$IFDEF CLR}
|
|
Save.Free;
|
|
{$ELSE}
|
|
FreeMem(Save);
|
|
{$ENDIF CLR}
|
|
Current.Left := nil;
|
|
end
|
|
end;
|
|
end;
|
|
end;
|
|
{$ENDIF RECURSIVE}
|
|
FCount := 0;
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.Clone: IInterface;
|
|
var
|
|
NewTree: TJclIntfBinaryTree;
|
|
|
|
function CloneNode(Node, Parent: PJclIntfBinaryNode): PJclIntfBinaryNode;
|
|
begin
|
|
if Node <> nil then
|
|
begin
|
|
{$IFDEF CLR}
|
|
Result := TJclIntfBinaryNode.Create;
|
|
{$ELSE}
|
|
GetMem(Result, SizeOf(TJclIntfBinaryNode));
|
|
{$ENDIF CLR}
|
|
Result.Obj := Node.Obj;
|
|
Result.Color := Node.Color;
|
|
Result.Parent := Parent;
|
|
Result.Left := CloneNode(Node.Left, Result); // recursive call
|
|
Result.Right := CloneNode(Node.Right, Result); // recursive call
|
|
end
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
begin
|
|
NewTree := TJclIntfBinaryTree.Create(FComparator);
|
|
NewTree.FCount := FCount;
|
|
NewTree.FRoot := CloneNode(FRoot, nil);
|
|
Result := NewTree;
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.Contains(AInterface: IInterface): Boolean;
|
|
var
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
Comp: Integer;
|
|
|
|
{$IFDEF RECURSIVE}
|
|
function ContainsChild(Node: PJclIntfBinaryNode): Boolean;
|
|
begin
|
|
Result := False;
|
|
if Node = nil then
|
|
Exit;
|
|
Comp := FComparator(Node.Obj, AInterface);
|
|
if Comp = 0 then
|
|
Result := True
|
|
else
|
|
if Comp > 0 then
|
|
Result := ContainsChild(Node.Left)
|
|
else
|
|
Result := ContainsChild(Node.Right);
|
|
end;
|
|
{$ELSE}
|
|
var
|
|
Current: PJclIntfBinaryNode;
|
|
{$ENDIF RECURSIVE}
|
|
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AInterface = nil then
|
|
Exit;
|
|
{$IFDEF RECURSIVE}
|
|
// recursive version
|
|
Result := ContainsChild(FRoot);
|
|
{$ELSE}
|
|
// iterative version
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Comp := FComparator(Current.Obj, AInterface);
|
|
if Comp = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
{$ENDIF RECURSIVE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.ContainsAll(ACollection: IJclIntfCollection): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while Result and It.HasNext do
|
|
Result := Contains(It.Next);
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.Equals(ACollection: IJclIntfCollection): Boolean;
|
|
var
|
|
It, ItSelf: IJclIntfIterator;
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
if FCount <> ACollection.Size then
|
|
Exit;
|
|
It := ACollection.First;
|
|
ItSelf := First;
|
|
while ItSelf.HasNext do
|
|
if FComparator(ItSelf.Next, It.Next) <> 0 then
|
|
Exit;
|
|
Result := True;
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.First: IJclIntfIterator;
|
|
begin
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TPreOrderIntfItr.Create(Self, FRoot);
|
|
toOrder:
|
|
Result := TInOrderIntfItr.Create(Self, FRoot);
|
|
toPostOrder:
|
|
Result := TPostOrderIntfItr.Create(Self, FRoot);
|
|
end;
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.GetTraverseOrder: TJclTraverseOrder;
|
|
begin
|
|
Result := FTraverseOrder;
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.IsEmpty: Boolean;
|
|
begin
|
|
Result := FCount = 0;
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.Last: IJclIntfIterator;
|
|
var
|
|
Start: PJclIntfBinaryNode;
|
|
begin
|
|
Start := FRoot;
|
|
case FTraverseOrder of
|
|
toPreOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Right <> nil do
|
|
Start := Start.Right;
|
|
Result := TPreOrderIntfItr.Create(Self, Start);
|
|
end;
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Right <> nil do
|
|
Start := Start.Right;
|
|
Result := TInOrderIntfItr.Create(Self, Start);
|
|
end;
|
|
toPostOrder:
|
|
Result := TPostOrderIntfItr.Create(Self, Start);
|
|
end;
|
|
end;
|
|
|
|
procedure TJclIntfBinaryTree.RotateLeft(Node: PJclIntfBinaryNode);
|
|
var
|
|
TempNode: PJclIntfBinaryNode;
|
|
begin
|
|
if Node = nil then
|
|
Exit;
|
|
TempNode := Node.Right;
|
|
// if TempNode = nil then Exit;
|
|
Node.Right := TempNode.Left;
|
|
if TempNode.Left <> nil then
|
|
TempNode.Left.Parent := Node;
|
|
TempNode.Parent := Node.Parent;
|
|
if Node.Parent = nil then
|
|
FRoot := TempNode
|
|
else
|
|
if Node.Parent.Left = Node then
|
|
Node.Parent.Left := TempNode
|
|
else
|
|
Node.Parent.Right := TempNode;
|
|
TempNode.Left := Node;
|
|
Node.Parent := TempNode;
|
|
end;
|
|
|
|
procedure TJclIntfBinaryTree.RotateRight(Node: PJclIntfBinaryNode);
|
|
var
|
|
TempNode: PJclIntfBinaryNode;
|
|
begin
|
|
if Node = nil then
|
|
Exit;
|
|
TempNode := Node.Left;
|
|
// if TempNode = nil then Exit;
|
|
Node.Left := TempNode.Right;
|
|
if TempNode.Right <> nil then
|
|
TempNode.Right.Parent := Node;
|
|
TempNode.Parent := Node.Parent;
|
|
if Node.Parent = nil then
|
|
FRoot := TempNode
|
|
else
|
|
if Node.Parent.Right = Node then
|
|
Node.Parent.Right := TempNode
|
|
else
|
|
Node.Parent.Left := TempNode;
|
|
TempNode.Right := Node;
|
|
Node.Parent := TempNode;
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.Remove(AInterface: IInterface): Boolean;
|
|
var
|
|
Current: PJclIntfBinaryNode;
|
|
Node: PJclIntfBinaryNode;
|
|
Save: PJclIntfBinaryNode;
|
|
Comp: Integer;
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
|
|
procedure Correction(Node: PJclIntfBinaryNode);
|
|
var
|
|
TempNode: PJclIntfBinaryNode;
|
|
begin
|
|
while (Node <> FRoot) and (Node.Color = tcBlack) do
|
|
begin
|
|
if Node = Node.Parent.Left then
|
|
begin
|
|
TempNode := Node.Parent.Right;
|
|
if TempNode = nil then
|
|
begin
|
|
Node := Node.Parent;
|
|
Continue;
|
|
end;
|
|
if TempNode.Color = tcRed then
|
|
begin
|
|
TempNode.Color := tcBlack;
|
|
Node.Parent.Color := tcRed;
|
|
RotateLeft(Node.Parent);
|
|
TempNode := Node.Parent.Right;
|
|
end;
|
|
if (TempNode.Left <> nil) and (TempNode.Left.Color = tcBlack) and
|
|
(TempNode.Right <> nil) and (TempNode.Right.Color = tcBlack) then
|
|
begin
|
|
TempNode.Color := tcRed;
|
|
Node := Node.Parent;
|
|
end
|
|
else
|
|
begin
|
|
if (TempNode.Right <> nil) and (TempNode.Right.Color = tcBlack) then
|
|
begin
|
|
TempNode.Left.Color := tcBlack;
|
|
TempNode.Color := tcRed;
|
|
RotateRight(TempNode);
|
|
TempNode := Node.Parent.Right;
|
|
end;
|
|
TempNode.Color := Node.Parent.Color;
|
|
Node.Parent.Color := tcBlack;
|
|
if TempNode.Right <> nil then
|
|
TempNode.Right.Color := tcBlack;
|
|
RotateLeft(Node.Parent);
|
|
Node := FRoot;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TempNode := Node.Parent.Left;
|
|
if TempNode = nil then
|
|
begin
|
|
Node := Node.Parent;
|
|
Continue;
|
|
end;
|
|
if TempNode.Color = tcRed then
|
|
begin
|
|
TempNode.Color := tcBlack;
|
|
Node.Parent.Color := tcRed;
|
|
RotateRight(Node.Parent);
|
|
TempNode := Node.Parent.Left;
|
|
end;
|
|
if (TempNode.Left.Color = tcBlack) and (TempNode.Right.Color = tcBlack) then
|
|
begin
|
|
TempNode.Color := tcRed;
|
|
Node := Node.Parent;
|
|
end
|
|
else
|
|
begin
|
|
if TempNode.Left.Color = tcBlack then
|
|
begin
|
|
TempNode.Right.Color := tcBlack;
|
|
TempNode.Color := tcRed;
|
|
RotateLeft(TempNode);
|
|
TempNode := Node.Parent.Left;
|
|
end;
|
|
TempNode.Color := Node.Parent.Color;
|
|
Node.Parent.Color := tcBlack;
|
|
if TempNode.Left <> nil then
|
|
TempNode.Left.Color := tcBlack;
|
|
RotateRight(Node.Parent);
|
|
Node := FRoot;
|
|
end;
|
|
end;
|
|
end;
|
|
Node.Color := tcBlack;
|
|
end;
|
|
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AInterface = nil then
|
|
Exit;
|
|
// locate AInterface in the tree
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Comp := FComparator(AInterface, Current.Obj);
|
|
if Comp = 0 then
|
|
Break
|
|
else
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
if Current = nil then
|
|
Exit;
|
|
// Remove
|
|
if (Current.Left = nil) or (Current.Right = nil) then
|
|
Save := Current
|
|
else
|
|
begin // Successor in Save
|
|
if Current.Right <> nil then
|
|
begin
|
|
Save := Current.Right;
|
|
while Save.Left <> nil do // Minimum
|
|
Save := Save.Left;
|
|
end
|
|
else
|
|
begin
|
|
Save := Current.Parent;
|
|
while (Save <> nil) and (Current = Save.Right) do
|
|
begin
|
|
Current := Save;
|
|
Save := Save.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
if Save.Left <> nil then
|
|
Node := Save.Left
|
|
else
|
|
Node := Save.Right;
|
|
if Node <> nil then
|
|
begin
|
|
Node.Parent := Save.Parent;
|
|
if Save.Parent = nil then
|
|
FRoot := Node
|
|
else
|
|
if Save = Save.Parent.Left then
|
|
Save.Parent.Left := Node
|
|
else
|
|
Save.Parent.Right := Node;
|
|
if Save.Color = tcBlack then
|
|
Correction(Node);
|
|
end
|
|
else
|
|
if Save.Parent = nil then
|
|
FRoot := nil
|
|
else
|
|
begin
|
|
if Save.Color = tcBlack then
|
|
Correction(Save);
|
|
if Save.Parent <> nil then
|
|
if Save = Save.Parent.Left then
|
|
Save.Parent.Left := nil
|
|
else
|
|
if Save = Save.Parent.Right then
|
|
Save.Parent.Right := nil
|
|
end;
|
|
{$IFDEF CLR}
|
|
Save.Free;
|
|
{$ELSE}
|
|
FreeMem(Save);
|
|
{$ENDIF CLR}
|
|
Dec(FCount);
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.RemoveAll(ACollection: IJclIntfCollection): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Remove(It.Next) and Result;
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.RetainAll(ACollection: IJclIntfCollection): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := First;
|
|
while It.HasNext do
|
|
if not ACollection.Contains(It.Next) then
|
|
It.Remove;
|
|
end;
|
|
|
|
procedure TJclIntfBinaryTree.SetTraverseOrder(Value: TJclTraverseOrder);
|
|
begin
|
|
FTraverseOrder := Value;
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.Size: Integer;
|
|
begin
|
|
Result := FCount;
|
|
end;
|
|
|
|
//=== { TJclStrBinaryTree } ==================================================
|
|
|
|
constructor TJclStrBinaryTree.Create(AComparator: TStrCompare = nil);
|
|
begin
|
|
inherited Create;
|
|
if Assigned(AComparator) then
|
|
FComparator := AComparator
|
|
else
|
|
FComparator := @StrSimpleCompare;
|
|
FTraverseOrder := toPreOrder;
|
|
end;
|
|
|
|
destructor TJclStrBinaryTree.Destroy;
|
|
begin
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJclStrBinaryTree.Add(const AString: string): Boolean;
|
|
var
|
|
NewNode: PJclStrBinaryNode;
|
|
Current, Save: PJclStrBinaryNode;
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AString = '' then
|
|
Exit;
|
|
{$IFDEF CLR}
|
|
NewNode := TJclStrBinaryNode.Create;
|
|
{$ELSE}
|
|
NewNode := AllocMem(SizeOf(TJclStrBinaryNode));
|
|
{$ENDIF CLR}
|
|
NewNode.Str := AString;
|
|
// Insert into right place
|
|
Save := nil;
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Save := Current;
|
|
if FComparator(NewNode.Str, Current.Str) < 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
NewNode.Parent := Save;
|
|
if Save = nil then
|
|
FRoot := NewNode
|
|
else
|
|
if FComparator(NewNode.Str, Save.Str) < 0 then
|
|
Save.Left := NewNode
|
|
else
|
|
Save.Right := NewNode;
|
|
// RB balanced
|
|
NewNode.Color := tcRed;
|
|
while (NewNode <> FRoot) and (NewNode.Parent.Color = tcRed) do
|
|
begin
|
|
if (NewNode.Parent.Parent <> nil) and (NewNode.Parent = NewNode.Parent.Parent.Left) then
|
|
begin
|
|
Current := NewNode.Parent.Parent.Right;
|
|
if (Current <> nil) and (Current.Color = tcRed) then
|
|
begin
|
|
NewNode.Parent.Color := tcBlack;
|
|
Current.Color := tcBlack;
|
|
NewNode.Parent.Parent.Color := tcRed;
|
|
NewNode := NewNode.Parent.Parent;
|
|
end
|
|
else
|
|
begin
|
|
if NewNode = NewNode.Parent.Right then
|
|
begin
|
|
NewNode := NewNode.Parent;
|
|
RotateLeft(NewNode);
|
|
end;
|
|
NewNode.Parent.Color := tcBlack;
|
|
NewNode.Parent.Parent.Color := tcRed;
|
|
RotateRight(NewNode.Parent.Parent);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if NewNode.Parent.Parent = nil then
|
|
Current := nil
|
|
else
|
|
Current := NewNode.Parent.Parent.Left;
|
|
if (Current <> nil) and (Current.Color = tcRed) then
|
|
begin
|
|
NewNode.Parent.Color := tcBlack;
|
|
Current.Color := tcBlack;
|
|
NewNode.Parent.Parent.Color := tcRed;
|
|
NewNode := NewNode.Parent.Parent;
|
|
end
|
|
else
|
|
begin
|
|
if NewNode = NewNode.Parent.Left then
|
|
begin
|
|
NewNode := NewNode.Parent;
|
|
RotateRight(NewNode);
|
|
end;
|
|
NewNode.Parent.Color := tcBlack;
|
|
if NewNode.Parent.Parent <> nil then
|
|
NewNode.Parent.Parent.Color := tcRed;
|
|
RotateLeft(NewNode.Parent.Parent);
|
|
end;
|
|
end;
|
|
end;
|
|
FRoot.Color := tcBlack;
|
|
Inc(FCount);
|
|
Result := True;
|
|
end;
|
|
|
|
function TJclStrBinaryTree.AddAll(ACollection: IJclStrCollection): Boolean;
|
|
var
|
|
It: IJclStrIterator;
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Add(It.Next) or Result;
|
|
end;
|
|
{
|
|
|
|
function TJclStrBinaryTree.GetAsStrings: TStrings;
|
|
begin
|
|
Result := TStringList.Create;
|
|
try
|
|
AppendToStrings(Result);
|
|
except
|
|
Result.Free;
|
|
raise;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclStrBinaryTree.LoadFromStrings(Strings: TStrings);
|
|
begin
|
|
Clear;
|
|
AppendFromStrings(Strings);
|
|
end;
|
|
|
|
procedure TJclStrBinaryTree.AppendToStrings(Strings: TStrings);
|
|
var
|
|
It: IJclStrIterator;
|
|
begin
|
|
It := First;
|
|
Strings.BeginUpdate;
|
|
try
|
|
while It.HasNext do
|
|
Strings.Add(It.Next);
|
|
finally
|
|
Strings.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclStrBinaryTree.SaveToStrings(Strings: TStrings);
|
|
begin
|
|
Strings.Clear;
|
|
AppendToStrings(Strings);
|
|
end;
|
|
|
|
procedure TJclStrBinaryTree.AppendFromStrings(Strings: TStrings);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to Strings.Count - 1 do
|
|
Add(Strings[I]);
|
|
end;
|
|
|
|
function TJclStrBinaryTree.GetAsDelimited(Separator: string): string;
|
|
var
|
|
It: IJclStrIterator;
|
|
begin
|
|
It := First;
|
|
Result := '';
|
|
if It.HasNext then
|
|
Result := It.Next;
|
|
while It.HasNext do
|
|
Result := Result + Separator + It.Next;
|
|
end;
|
|
|
|
procedure TJclStrBinaryTree.LoadDelimited(AString, Separator: string);
|
|
begin
|
|
Clear;
|
|
AppendDelimited(AString, Separator);
|
|
end;
|
|
|
|
procedure TJclStrBinaryTree.AppendDelimited(AString, Separator: string);
|
|
begin
|
|
DCLAppendDelimited(Self, AString, Separator);
|
|
end;
|
|
}
|
|
|
|
procedure TJclStrBinaryTree.Clear;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
|
|
{$IFDEF RECURSIVE}
|
|
procedure FreeChild(Node: PJclStrBinaryNode);
|
|
begin
|
|
if Node.Left <> nil then
|
|
FreeChild(Node.Left);
|
|
if Node.Right <> nil then
|
|
FreeChild(Node.Right);
|
|
Node.Str := ''; // Force Release
|
|
FreeMem(Node);
|
|
end;
|
|
{$ELSE}
|
|
var
|
|
Current: PJclStrBinaryNode;
|
|
Save: PJclStrBinaryNode;
|
|
{$ENDIF RECURSIVE}
|
|
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
{$IFDEF RECURSIVE}
|
|
// recursive version
|
|
if FRoot <> nil then
|
|
begin
|
|
FreeChild(FRoot);
|
|
FRoot := nil;
|
|
end;
|
|
{$ELSE}
|
|
// iterative version
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
if Current.Right <> nil then
|
|
Current := Current.Right
|
|
else
|
|
begin
|
|
Current.Str := ''; // Force Release
|
|
if Current.Parent = nil then // Root
|
|
begin
|
|
{$IFDEF CLR}
|
|
Current.Free;
|
|
{$ELSE}
|
|
FreeMem(Current);
|
|
{$ENDIF CLR}
|
|
Current := nil;
|
|
FRoot := nil;
|
|
end
|
|
else
|
|
begin
|
|
Save := Current;
|
|
Current := Current.Parent;
|
|
if Save = Current.Right then // True = from Right
|
|
begin
|
|
{$IFDEF CLR}
|
|
Save.Free;
|
|
{$ELSE}
|
|
FreeMem(Save);
|
|
{$ENDIF CLR}
|
|
Current.Right := nil;
|
|
end
|
|
else
|
|
begin
|
|
{$IFDEF CLR}
|
|
Save.Free;
|
|
{$ELSE}
|
|
FreeMem(Save);
|
|
{$ENDIF CLR}
|
|
Current.Left := nil;
|
|
end
|
|
end;
|
|
end;
|
|
end;
|
|
{$ENDIF RECURSIVE}
|
|
FCount := 0;
|
|
end;
|
|
|
|
function TJclStrBinaryTree.Clone: TObject;
|
|
var
|
|
NewTree: TJclStrBinaryTree;
|
|
|
|
function CloneNode(Node, Parent: PJclStrBinaryNode): PJclStrBinaryNode;
|
|
begin
|
|
if Node <> nil then
|
|
begin
|
|
{$IFDEF CLR}
|
|
Result := TJclStrBinaryNode.Create;
|
|
{$ELSE}
|
|
GetMem(Result, SizeOf(TJclStrBinaryNode));
|
|
{$ENDIF CLR}
|
|
Result.Str := Node.Str;
|
|
Result.Color := Node.Color;
|
|
Result.Parent := Parent;
|
|
Result.Left := CloneNode(Node.Left, Result); // recursive call
|
|
Result.Right := CloneNode(Node.Right, Result); // recursive call
|
|
end
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
begin
|
|
NewTree := TJclStrBinaryTree.Create(FComparator);
|
|
NewTree.FCount := FCount;
|
|
NewTree.FRoot := CloneNode(FRoot, nil);
|
|
Result := NewTree;
|
|
end;
|
|
|
|
function TJclStrBinaryTree.Contains(const AString: string): Boolean;
|
|
var
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
Comp: Integer;
|
|
|
|
{$IFDEF RECURSIVE}
|
|
function ContainsChild(Node: PJclStrBinaryNode): Boolean;
|
|
begin
|
|
Result := False;
|
|
if Node = nil then
|
|
Exit;
|
|
Comp := FComparator(Node.Str, AString);
|
|
if Comp = 0 then
|
|
Result := True
|
|
else
|
|
if Comp > 0 then
|
|
Result := ContainsChild(Node.Left)
|
|
else
|
|
Result := ContainsChild(Node.Right)
|
|
end;
|
|
{$ELSE}
|
|
var
|
|
Current: PJclStrBinaryNode;
|
|
{$ENDIF RECURSIVE}
|
|
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AString = '' then
|
|
Exit;
|
|
{$IFDEF RECURSIVE}
|
|
// recursive version
|
|
Result := ContainsChild(FRoot);
|
|
{$ELSE}
|
|
// iterative version
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Comp := FComparator(Current.Str, AString);
|
|
if Comp = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
{$ENDIF RECURSIVE}
|
|
end;
|
|
|
|
function TJclStrBinaryTree.ContainsAll(ACollection: IJclStrCollection): Boolean;
|
|
var
|
|
It: IJclStrIterator;
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while Result and It.HasNext do
|
|
Result := Contains(It.Next);
|
|
end;
|
|
|
|
function TJclStrBinaryTree.Equals(ACollection: IJclStrCollection): Boolean;
|
|
var
|
|
It, ItSelf: IJclStrIterator;
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
if FCount <> ACollection.Size then
|
|
Exit;
|
|
It := ACollection.First;
|
|
ItSelf := First;
|
|
while ItSelf.HasNext do
|
|
if FComparator(ItSelf.Next, It.Next) <> 0 then
|
|
Exit;
|
|
Result := True;
|
|
end;
|
|
|
|
function TJclStrBinaryTree.First: IJclStrIterator;
|
|
begin
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TPreOrderStrItr.Create(Self, FRoot);
|
|
toOrder:
|
|
Result := TInOrderStrItr.Create(Self, FRoot);
|
|
toPostOrder:
|
|
Result := TPostOrderStrItr.Create(Self, FRoot);
|
|
end;
|
|
end;
|
|
|
|
function TJclStrBinaryTree.GetTraverseOrder: TJclTraverseOrder;
|
|
begin
|
|
Result := FTraverseOrder;
|
|
end;
|
|
|
|
function TJclStrBinaryTree.IsEmpty: Boolean;
|
|
begin
|
|
Result := FCount = 0;
|
|
end;
|
|
|
|
function TJclStrBinaryTree.Last: IJclStrIterator;
|
|
var
|
|
Start: PJclStrBinaryNode;
|
|
begin
|
|
Start := FRoot;
|
|
case FTraverseOrder of
|
|
toPreOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Right <> nil do
|
|
Start := Start.Right;
|
|
Result := TPreOrderStrItr.Create(Self, Start);
|
|
end;
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Right <> nil do
|
|
Start := Start.Right;
|
|
Result := TInOrderStrItr.Create(Self, Start);
|
|
end;
|
|
toPostOrder:
|
|
Result := TPostOrderStrItr.Create(Self, Start);
|
|
end;
|
|
end;
|
|
|
|
function TJclStrBinaryTree.Remove(const AString: string): Boolean;
|
|
var
|
|
Current: PJclStrBinaryNode;
|
|
Node: PJclStrBinaryNode;
|
|
Save: PJclStrBinaryNode;
|
|
Comp: Integer;
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
|
|
procedure Correction(Node: PJclStrBinaryNode);
|
|
var
|
|
TempNode: PJclStrBinaryNode;
|
|
begin
|
|
while (Node <> FRoot) and (Node.Color = tcBlack) do
|
|
begin
|
|
if Node = Node.Parent.Left then
|
|
begin
|
|
TempNode := Node.Parent.Right;
|
|
if TempNode = nil then
|
|
begin
|
|
Node := Node.Parent;
|
|
Continue;
|
|
end;
|
|
if TempNode.Color = tcRed then
|
|
begin
|
|
TempNode.Color := tcBlack;
|
|
Node.Parent.Color := tcRed;
|
|
RotateLeft(Node.Parent);
|
|
TempNode := Node.Parent.Right;
|
|
end;
|
|
if (TempNode.Left <> nil) and (TempNode.Left.Color = tcBlack) and
|
|
(TempNode.Right <> nil) and (TempNode.Right.Color = tcBlack) then
|
|
begin
|
|
TempNode.Color := tcRed;
|
|
Node := Node.Parent;
|
|
end
|
|
else
|
|
begin
|
|
if (TempNode.Right <> nil) and (TempNode.Right.Color = tcBlack) then
|
|
begin
|
|
TempNode.Left.Color := tcBlack;
|
|
TempNode.Color := tcRed;
|
|
RotateRight(TempNode);
|
|
TempNode := Node.Parent.Right;
|
|
end;
|
|
TempNode.Color := Node.Parent.Color;
|
|
Node.Parent.Color := tcBlack;
|
|
if TempNode.Right <> nil then
|
|
TempNode.Right.Color := tcBlack;
|
|
RotateLeft(Node.Parent);
|
|
Node := FRoot;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TempNode := Node.Parent.Left;
|
|
if TempNode = nil then
|
|
begin
|
|
Node := Node.Parent;
|
|
Continue;
|
|
end;
|
|
if TempNode.Color = tcRed then
|
|
begin
|
|
TempNode.Color := tcBlack;
|
|
Node.Parent.Color := tcRed;
|
|
RotateRight(Node.Parent);
|
|
TempNode := Node.Parent.Left;
|
|
end;
|
|
if (TempNode.Left.Color = tcBlack) and (TempNode.Right.Color = tcBlack) then
|
|
begin
|
|
TempNode.Color := tcRed;
|
|
Node := Node.Parent;
|
|
end
|
|
else
|
|
begin
|
|
if TempNode.Left.Color = tcBlack then
|
|
begin
|
|
TempNode.Right.Color := tcBlack;
|
|
TempNode.Color := tcRed;
|
|
RotateLeft(TempNode);
|
|
TempNode := Node.Parent.Left;
|
|
end;
|
|
TempNode.Color := Node.Parent.Color;
|
|
Node.Parent.Color := tcBlack;
|
|
if TempNode.Left <> nil then
|
|
TempNode.Left.Color := tcBlack;
|
|
RotateRight(Node.Parent);
|
|
Node := FRoot;
|
|
end;
|
|
end
|
|
end;
|
|
Node.Color := tcBlack;
|
|
end;
|
|
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AString = '' then
|
|
Exit;
|
|
// locate AObject in the tree
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Comp := FComparator(AString, Current.Str);
|
|
if Comp = 0 then
|
|
Break
|
|
else
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
if Current = nil then
|
|
Exit;
|
|
// Remove
|
|
if (Current.Left = nil) or (Current.Right = nil) then
|
|
Save := Current
|
|
else
|
|
begin // Successor in Save
|
|
if Current.Right <> nil then
|
|
begin
|
|
Save := Current.Right;
|
|
while Save.Left <> nil do // Minimum
|
|
Save := Save.Left;
|
|
end
|
|
else
|
|
begin
|
|
Save := Current.Parent;
|
|
while (Save <> nil) and (Current = Save.Right) do
|
|
begin
|
|
Current := Save;
|
|
Save := Save.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
if Save.Left <> nil then
|
|
Node := Save.Left
|
|
else
|
|
Node := Save.Right;
|
|
if Node <> nil then
|
|
begin
|
|
Node.Parent := Save.Parent;
|
|
if Save.Parent = nil then
|
|
FRoot := Node
|
|
else
|
|
if Save = Save.Parent.Left then
|
|
Save.Parent.Left := Node
|
|
else
|
|
Save.Parent.Right := Node;
|
|
if Save.Color = tcBlack then // Correction
|
|
Correction(Node);
|
|
end
|
|
else
|
|
if Save.Parent = nil then
|
|
FRoot := nil
|
|
else
|
|
begin
|
|
if Save.Color = tcBlack then // Correction
|
|
Correction(Save);
|
|
if Save.Parent <> nil then
|
|
if Save = Save.Parent.Left then
|
|
Save.Parent.Left := nil
|
|
else
|
|
if Save = Save.Parent.Right then
|
|
Save.Parent.Right := nil
|
|
end;
|
|
{$IFDEF CLR}
|
|
Save.Free;
|
|
{$ELSE}
|
|
FreeMem(Save);
|
|
{$ENDIF CLR}
|
|
Dec(FCount);
|
|
end;
|
|
|
|
function TJclStrBinaryTree.RemoveAll(ACollection: IJclStrCollection): Boolean;
|
|
var
|
|
It: IJclStrIterator;
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Remove(It.Next) and Result;
|
|
end;
|
|
|
|
function TJclStrBinaryTree.RetainAll(ACollection: IJclStrCollection): Boolean;
|
|
var
|
|
It: IJclStrIterator;
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := First;
|
|
while It.HasNext do
|
|
if not ACollection.Contains(It.Next) then
|
|
It.Remove;
|
|
end;
|
|
|
|
procedure TJclStrBinaryTree.RotateLeft(Node: PJclStrBinaryNode);
|
|
var
|
|
TempNode: PJclStrBinaryNode;
|
|
begin
|
|
if Node = nil then
|
|
Exit;
|
|
TempNode := Node.Right;
|
|
// if TempNode = nil then Exit;
|
|
Node.Right := TempNode.Left;
|
|
if TempNode.Left <> nil then
|
|
TempNode.Left.Parent := Node;
|
|
TempNode.Parent := Node.Parent;
|
|
if Node.Parent = nil then
|
|
FRoot := TempNode
|
|
else
|
|
if Node.Parent.Left = Node then
|
|
Node.Parent.Left := TempNode
|
|
else
|
|
Node.Parent.Right := TempNode;
|
|
TempNode.Left := Node;
|
|
Node.Parent := TempNode;
|
|
end;
|
|
|
|
procedure TJclStrBinaryTree.RotateRight(Node: PJclStrBinaryNode);
|
|
var
|
|
TempNode: PJclStrBinaryNode;
|
|
begin
|
|
if Node = nil then
|
|
Exit;
|
|
TempNode := Node.Left;
|
|
// if TempNode = nil then Exit;
|
|
Node.Left := TempNode.Right;
|
|
if TempNode.Right <> nil then
|
|
TempNode.Right.Parent := Node;
|
|
TempNode.Parent := Node.Parent;
|
|
if Node.Parent = nil then
|
|
FRoot := TempNode
|
|
else
|
|
if Node.Parent.Right = Node then
|
|
Node.Parent.Right := TempNode
|
|
else
|
|
Node.Parent.Left := TempNode;
|
|
TempNode.Right := Node;
|
|
Node.Parent := TempNode;
|
|
end;
|
|
|
|
procedure TJclStrBinaryTree.SetTraverseOrder(Value: TJclTraverseOrder);
|
|
begin
|
|
FTraverseOrder := Value;
|
|
end;
|
|
|
|
function TJclStrBinaryTree.Size: Integer;
|
|
begin
|
|
Result := FCount;
|
|
end;
|
|
|
|
//=== { TJclBinaryTree } =====================================================
|
|
|
|
constructor TJclBinaryTree.Create(AComparator: TCompare = nil);
|
|
begin
|
|
inherited Create;
|
|
if Assigned(AComparator) then
|
|
FComparator := AComparator
|
|
else
|
|
FComparator := @SimpleCompare;
|
|
FTraverseOrder := toPreOrder;
|
|
end;
|
|
|
|
destructor TJclBinaryTree.Destroy;
|
|
begin
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJclBinaryTree.Add(AObject: TObject): Boolean;
|
|
var
|
|
NewNode: PJclBinaryNode;
|
|
Current, Save: PJclBinaryNode;
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AObject = nil then
|
|
Exit;
|
|
{$IFDEF CLR}
|
|
NewNode := TJclBinaryNode.Create;
|
|
{$ELSE}
|
|
NewNode := AllocMem(SizeOf(TJclBinaryNode));
|
|
{$ENDIF CLR}
|
|
NewNode.Obj := AObject;
|
|
// Insert into right place
|
|
Save := nil;
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Save := Current;
|
|
if FComparator(NewNode.Obj, Current.Obj) < 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
NewNode.Parent := Save;
|
|
if Save = nil then
|
|
FRoot := NewNode
|
|
else
|
|
if FComparator(NewNode.Obj, Save.Obj) < 0 then
|
|
Save.Left := NewNode
|
|
else
|
|
Save.Right := NewNode;
|
|
// RB balanced
|
|
NewNode.Color := tcRed;
|
|
while (NewNode <> FRoot) and (NewNode.Parent.Color = tcRed) do
|
|
begin
|
|
if (NewNode.Parent.Parent <> nil) and (NewNode.Parent = NewNode.Parent.Parent.Left) then
|
|
begin
|
|
Current := NewNode.Parent.Parent.Right;
|
|
if Current.Color = tcRed then
|
|
begin
|
|
NewNode.Parent.Color := tcBlack;
|
|
Current.Color := tcBlack;
|
|
NewNode.Parent.Parent.Color := tcRed;
|
|
NewNode := NewNode.Parent.Parent;
|
|
end
|
|
else
|
|
begin
|
|
if NewNode = NewNode.Parent.Right then
|
|
begin
|
|
NewNode := NewNode.Parent;
|
|
RotateLeft(NewNode);
|
|
end;
|
|
NewNode.Parent.Color := tcBlack;
|
|
NewNode.Parent.Parent.Color := tcRed;
|
|
RotateRight(NewNode.Parent.Parent);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if NewNode.Parent.Parent = nil then
|
|
Current := nil
|
|
else
|
|
Current := NewNode.Parent.Parent.Left;
|
|
if (Current <> nil) and (Current.Color = tcRed) then
|
|
begin
|
|
NewNode.Parent.Color := tcBlack;
|
|
Current.Color := tcBlack;
|
|
NewNode.Parent.Parent.Color := tcRed;
|
|
NewNode := NewNode.Parent.Parent;
|
|
end
|
|
else
|
|
begin
|
|
if NewNode = NewNode.Parent.Left then
|
|
begin
|
|
NewNode := NewNode.Parent;
|
|
RotateRight(NewNode);
|
|
end;
|
|
NewNode.Parent.Color := tcBlack;
|
|
if NewNode.Parent.Parent <> nil then
|
|
NewNode.Parent.Parent.Color := tcRed;
|
|
RotateLeft(NewNode.Parent.Parent);
|
|
end;
|
|
end;
|
|
end;
|
|
FRoot.Color := tcBlack;
|
|
Inc(FCount);
|
|
Result := True;
|
|
end;
|
|
|
|
function TJclBinaryTree.AddAll(ACollection: IJclCollection): Boolean;
|
|
var
|
|
It: IJclIterator;
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Add(It.Next) or Result;
|
|
end;
|
|
|
|
procedure TJclBinaryTree.Clear;
|
|
{$IFDEF THREADSAFE}
|
|
var
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
|
|
{$IFDEF RECURSIVE}
|
|
procedure FreeChild(Node: PJclBinaryNode);
|
|
begin
|
|
if Node.Left <> nil then
|
|
FreeChild(Node.Left);
|
|
if Node.Right <> nil then
|
|
FreeChild(Node.Right);
|
|
Node.Obj := nil; // Force Release
|
|
FreeMem(Node);
|
|
end;
|
|
{$ELSE}
|
|
var
|
|
Current: PJclBinaryNode;
|
|
Save: PJclBinaryNode;
|
|
{$ENDIF RECURSIVE}
|
|
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
{$IFDEF RECURSIVE}
|
|
// recursive version
|
|
if FRoot <> nil then
|
|
begin
|
|
FreeChild(FRoot);
|
|
FRoot := nil;
|
|
end;
|
|
{$ELSE}
|
|
// iterative version
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
if Current.Right <> nil then
|
|
Current := Current.Right
|
|
else
|
|
begin
|
|
Current.Obj := nil; // Force Release
|
|
if Current.Parent = nil then // Root
|
|
begin
|
|
{$IFDEF CLR}
|
|
Current.Free;
|
|
{$ELSE}
|
|
FreeMem(Current);
|
|
{$ENDIF CLR}
|
|
Current := nil;
|
|
FRoot := nil;
|
|
end
|
|
else
|
|
begin
|
|
Save := Current;
|
|
Current := Current.Parent;
|
|
if Save = Current.Right then // True = from Right
|
|
begin
|
|
{$IFDEF CLR}
|
|
Save.Free;
|
|
{$ELSE}
|
|
FreeMem(Save);
|
|
{$ENDIF CLR}
|
|
Current.Right := nil;
|
|
end
|
|
else
|
|
begin
|
|
{$IFDEF CLR}
|
|
Save.Free;
|
|
{$ELSE}
|
|
FreeMem(Save);
|
|
{$ENDIF CLR}
|
|
Current.Left := nil;
|
|
end
|
|
end;
|
|
end;
|
|
end;
|
|
{$ENDIF RECURSIVE}
|
|
FCount := 0;
|
|
end;
|
|
|
|
function TJclBinaryTree.Clone: TObject;
|
|
var
|
|
NewTree: TJclBinaryTree;
|
|
|
|
function CloneNode(Node, Parent: PJclBinaryNode): PJclBinaryNode;
|
|
begin
|
|
if Node <> nil then
|
|
begin
|
|
{$IFDEF CLR}
|
|
Result := TJclBinaryNode.Create;
|
|
{$ELSE}
|
|
GetMem(Result, SizeOf(TJclBinaryNode));
|
|
{$ENDIF CLR}
|
|
Result.Obj := Node.Obj;
|
|
Result.Color := Node.Color;
|
|
Result.Parent := Parent;
|
|
Result.Left := CloneNode(Node.Left, Result); // recursive call
|
|
Result.Right := CloneNode(Node.Right, Result); // recursive call
|
|
end
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
begin
|
|
NewTree := TJclBinaryTree.Create(FComparator);
|
|
NewTree.FCount := FCount;
|
|
NewTree.FRoot := CloneNode(FRoot, nil);
|
|
Result := NewTree;
|
|
end;
|
|
|
|
function TJclBinaryTree.Contains(AObject: TObject): Boolean;
|
|
var
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
Comp: Integer;
|
|
|
|
{$IFDEF RECURSIVE}
|
|
function ContainsChild(Node: PJclBinaryNode): Boolean;
|
|
begin
|
|
Result := False;
|
|
if Node = nil then
|
|
Exit;
|
|
Comp := FComparator(Node.Obj, AObject);
|
|
if Comp = 0 then
|
|
Result := True
|
|
else
|
|
if Comp > 0 then
|
|
Result := ContainsChild(Node.Left)
|
|
else
|
|
Result := ContainsChild(Node.Right);
|
|
end;
|
|
{$ELSE}
|
|
var
|
|
Current: PJclBinaryNode;
|
|
{$ENDIF RECURSIVE}
|
|
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AObject = nil then
|
|
Exit;
|
|
{$IFDEF RECURSIVE}
|
|
// recursive version
|
|
Result := ContainsChild(FRoot);
|
|
{$ELSE}
|
|
// iterative version
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Comp := FComparator(Current.Obj, AObject);
|
|
if Comp = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
{$ENDIF RECURSIVE}
|
|
end;
|
|
|
|
function TJclBinaryTree.ContainsAll(ACollection: IJclCollection): Boolean;
|
|
var
|
|
It: IJclIterator;
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while Result and It.HasNext do
|
|
Result := Contains(It.Next);
|
|
end;
|
|
|
|
function TJclBinaryTree.Equals(ACollection: IJclCollection): Boolean;
|
|
var
|
|
It, ItSelf: IJclIterator;
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
if FCount <> ACollection.Size then
|
|
Exit;
|
|
It := ACollection.First;
|
|
ItSelf := First;
|
|
while ItSelf.HasNext do
|
|
if FComparator(ItSelf.Next, It.Next) <> 0 then
|
|
Exit;
|
|
Result := True;
|
|
end;
|
|
|
|
function TJclBinaryTree.First: IJclIterator;
|
|
begin
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TPreOrderItr.Create(Self, FRoot);
|
|
toOrder:
|
|
Result := TInOrderItr.Create(Self, FRoot);
|
|
toPostOrder:
|
|
Result := TPostOrderItr.Create(Self, FRoot);
|
|
end;
|
|
end;
|
|
|
|
function TJclBinaryTree.GetTraverseOrder: TJclTraverseOrder;
|
|
begin
|
|
Result := FTraverseOrder;
|
|
end;
|
|
|
|
function TJclBinaryTree.IsEmpty: Boolean;
|
|
begin
|
|
Result := FCount = 0;
|
|
end;
|
|
|
|
function TJclBinaryTree.Last: IJclIterator;
|
|
var
|
|
Start: PJclBinaryNode;
|
|
begin
|
|
Start := FRoot;
|
|
case FTraverseOrder of
|
|
toPreOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Right <> nil do
|
|
Start := Start.Right;
|
|
Result := TPreOrderItr.Create(Self, Start);
|
|
end;
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Right <> nil do
|
|
Start := Start.Right;
|
|
Result := TInOrderItr.Create(Self, Start);
|
|
end;
|
|
toPostOrder:
|
|
Result := TPostOrderItr.Create(Self, Start);
|
|
end;
|
|
end;
|
|
|
|
function TJclBinaryTree.Remove(AObject: TObject): Boolean;
|
|
var
|
|
Current: PJclBinaryNode;
|
|
Node: PJclBinaryNode;
|
|
Save: PJclBinaryNode;
|
|
Comp: Integer;
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
|
|
procedure Correction(Node: PJclBinaryNode);
|
|
var
|
|
TempNode: PJclBinaryNode;
|
|
begin
|
|
while (Node <> FRoot) and (Node.Color = tcBlack) do
|
|
begin
|
|
if Node = Node.Parent.Left then
|
|
begin
|
|
TempNode := Node.Parent.Right;
|
|
if TempNode = nil then
|
|
begin
|
|
Node := Node.Parent;
|
|
Continue;
|
|
end;
|
|
if TempNode.Color = tcRed then
|
|
begin
|
|
TempNode.Color := tcBlack;
|
|
Node.Parent.Color := tcRed;
|
|
RotateLeft(Node.Parent);
|
|
TempNode := Node.Parent.Right;
|
|
end;
|
|
if (TempNode.Left <> nil) and (TempNode.Left.Color = tcBlack) and
|
|
(TempNode.Right <> nil) and (TempNode.Right.Color = tcBlack) then
|
|
begin
|
|
TempNode.Color := tcRed;
|
|
Node := Node.Parent;
|
|
end
|
|
else
|
|
begin
|
|
if (TempNode.Right <> nil) and (TempNode.Right.Color = tcBlack) then
|
|
begin
|
|
TempNode.Left.Color := tcBlack;
|
|
TempNode.Color := tcRed;
|
|
RotateRight(TempNode);
|
|
TempNode := Node.Parent.Right;
|
|
end;
|
|
TempNode.Color := Node.Parent.Color;
|
|
Node.Parent.Color := tcBlack;
|
|
if TempNode.Right <> nil then
|
|
TempNode.Right.Color := tcBlack;
|
|
RotateLeft(Node.Parent);
|
|
Node := FRoot;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TempNode := Node.Parent.Left;
|
|
if TempNode = nil then
|
|
begin
|
|
Node := Node.Parent;
|
|
Continue;
|
|
end;
|
|
if TempNode.Color = tcRed then
|
|
begin
|
|
TempNode.Color := tcBlack;
|
|
Node.Parent.Color := tcRed;
|
|
RotateRight(Node.Parent);
|
|
TempNode := Node.Parent.Left;
|
|
end;
|
|
if (TempNode.Left.Color = tcBlack) and (TempNode.Right.Color = tcBlack) then
|
|
begin
|
|
TempNode.Color := tcRed;
|
|
Node := Node.Parent;
|
|
end
|
|
else
|
|
begin
|
|
if TempNode.Left.Color = tcBlack then
|
|
begin
|
|
TempNode.Right.Color := tcBlack;
|
|
TempNode.Color := tcRed;
|
|
RotateLeft(TempNode);
|
|
TempNode := Node.Parent.Left;
|
|
end;
|
|
TempNode.Color := Node.Parent.Color;
|
|
Node.Parent.Color := tcBlack;
|
|
if TempNode.Left <> nil then
|
|
TempNode.Left.Color := tcBlack;
|
|
RotateRight(Node.Parent);
|
|
Node := FRoot;
|
|
end;
|
|
end
|
|
end;
|
|
Node.Color := tcBlack;
|
|
end;
|
|
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if AObject = nil then
|
|
Exit;
|
|
// locate AObject in the tree
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Comp := FComparator(AObject, Current.Obj);
|
|
if Comp = 0 then
|
|
Break
|
|
else
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
if Current = nil then
|
|
Exit;
|
|
// Remove
|
|
if (Current.Left = nil) or (Current.Right = nil) then
|
|
Save := Current
|
|
else
|
|
begin // Successor in Save
|
|
if Current.Right <> nil then
|
|
begin
|
|
Save := Current.Right;
|
|
while Save.Left <> nil do // Minimum
|
|
Save := Save.Left;
|
|
end
|
|
else
|
|
begin
|
|
Save := Current.Parent;
|
|
while (Save <> nil) and (Current = Save.Right) do
|
|
begin
|
|
Current := Save;
|
|
Save := Save.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
if Save.Left <> nil then
|
|
Node := Save.Left
|
|
else
|
|
Node := Save.Right;
|
|
if Node <> nil then
|
|
begin
|
|
Node.Parent := Save.Parent;
|
|
if Save.Parent = nil then
|
|
FRoot := Node
|
|
else
|
|
if Save = Save.Parent.Left then
|
|
Save.Parent.Left := Node
|
|
else
|
|
Save.Parent.Right := Node;
|
|
if Save.Color = tcBlack then // Correction
|
|
Correction(Node);
|
|
end
|
|
else
|
|
if Save.Parent = nil then
|
|
FRoot := nil
|
|
else
|
|
begin
|
|
if Save.Color = tcBlack then // Correction
|
|
Correction(Save);
|
|
if Save.Parent <> nil then
|
|
if Save = Save.Parent.Left then
|
|
Save.Parent.Left := nil
|
|
else
|
|
if Save = Save.Parent.Right then
|
|
Save.Parent.Right := nil
|
|
end;
|
|
{$IFDEF CLR}
|
|
Save.Free;
|
|
{$ELSE}
|
|
FreeMem(Save);
|
|
{$ENDIF CLR}
|
|
Dec(FCount);
|
|
end;
|
|
|
|
function TJclBinaryTree.RemoveAll(ACollection: IJclCollection): Boolean;
|
|
var
|
|
It: IJclIterator;
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Remove(It.Next) and Result;
|
|
end;
|
|
|
|
function TJclBinaryTree.RetainAll(ACollection: IJclCollection): Boolean;
|
|
var
|
|
It: IJclIterator;
|
|
{$IFDEF THREADSAFE}
|
|
CS: IInterface;
|
|
{$ENDIF THREADSAFE}
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
CS := EnterCriticalSection;
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := First;
|
|
while It.HasNext do
|
|
if not ACollection.Contains(It.Next) then
|
|
It.Remove;
|
|
end;
|
|
|
|
procedure TJclBinaryTree.RotateLeft(Node: PJclBinaryNode);
|
|
var
|
|
TempNode: PJclBinaryNode;
|
|
begin
|
|
if Node = nil then
|
|
Exit;
|
|
TempNode := Node.Right;
|
|
// if TempNode = nil then Exit;
|
|
Node.Right := TempNode.Left;
|
|
if TempNode.Left <> nil then
|
|
TempNode.Left.Parent := Node;
|
|
TempNode.Parent := Node.Parent;
|
|
if Node.Parent = nil then
|
|
FRoot := TempNode
|
|
else
|
|
if Node.Parent.Left = Node then
|
|
Node.Parent.Left := TempNode
|
|
else
|
|
Node.Parent.Right := TempNode;
|
|
TempNode.Left := Node;
|
|
Node.Parent := TempNode;
|
|
end;
|
|
|
|
procedure TJclBinaryTree.RotateRight(Node: PJclBinaryNode);
|
|
var
|
|
TempNode: PJclBinaryNode;
|
|
begin
|
|
if Node = nil then
|
|
Exit;
|
|
TempNode := Node.Left;
|
|
// if TempNode = nil then Exit;
|
|
Node.Left := TempNode.Right;
|
|
if TempNode.Right <> nil then
|
|
TempNode.Right.Parent := Node;
|
|
TempNode.Parent := Node.Parent;
|
|
if Node.Parent = nil then
|
|
FRoot := TempNode
|
|
else
|
|
if Node.Parent.Right = Node then
|
|
Node.Parent.Right := TempNode
|
|
else
|
|
Node.Parent.Left := TempNode;
|
|
TempNode.Right := Node;
|
|
Node.Parent := TempNode;
|
|
end;
|
|
|
|
procedure TJclBinaryTree.SetTraverseOrder(Value: TJclTraverseOrder);
|
|
begin
|
|
FTraverseOrder := Value;
|
|
end;
|
|
|
|
function TJclBinaryTree.Size: Integer;
|
|
begin
|
|
Result := FCount;
|
|
end;
|
|
|
|
// History:
|
|
|
|
// $Log: JclBinaryTrees.pas,v $
|
|
// Revision 1.9 2005/05/05 20:08:42 ahuser
|
|
// JCL.NET support
|
|
//
|
|
// Revision 1.8 2005/03/08 08:33:15 marquardt
|
|
// overhaul of exceptions and resourcestrings, minor style cleaning
|
|
//
|
|
// Revision 1.7 2005/03/04 06:40:25 marquardt
|
|
// changed overloaded constructors to constructor with default parameter (BCB friendly)
|
|
//
|
|
// Revision 1.6 2005/03/03 08:02:56 marquardt
|
|
// various style cleanings, bugfixes and improvements
|
|
//
|
|
// Revision 1.5 2005/03/02 09:59:30 dade2004
|
|
// Added
|
|
// -TJclStrCollection in JclContainerIntf
|
|
// Every common methods for IJclStrCollection are implemented here
|
|
//
|
|
// -Every class that implement IJclStrCollection now derive from TJclStrCollection instead of TJclAbstractContainer
|
|
// -Every abstract method in TJclStrCollection has been marked as "override" in descendent classes
|
|
//
|
|
// DCLAppendDelimited has been removed from JclAlgorothms, his body has been fixed for a bug and put into
|
|
// relative method in TJclStrCollection
|
|
//
|
|
// Revision 1.4 2005/02/27 11:36:20 marquardt
|
|
// fixed and secured Capacity/Grow mechanism, raise exceptions with efficient CreateResRec
|
|
//
|
|
// Revision 1.3 2005/02/27 07:27:47 marquardt
|
|
// changed interface names from I to IJcl, moved resourcestrings to JclResource.pas
|
|
//
|
|
// Revision 1.2 2005/02/26 16:42:08 marquardt
|
|
// deactivated THREADSAFE and fixed bugs stemming from that
|
|
//
|
|
// Revision 1.1 2005/02/24 03:57:10 rrossmair
|
|
// - donated DCL code, initial check-in
|
|
//
|
|
|
|
end.
|
|
|