123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669 |
- { Red Black Tree implementation.
- Copyright (c) 2013 by Inoussa OUEDRAOGO
- Inspired by ideas of Julienne Walker
- see http://www.eternallyconfuzzled.com/tuts/datastructures/jsw_tut_bst1.aspx
- The source code is distributed under the Library GNU
- General Public License with the following modification:
- - object files and libraries linked into an application may be
- distributed without source code.
- If you didn't receive a copy of the file COPYING, contact:
- Free Software Foundation
- 675 Mass Ave
- Cambridge, MA 02139
- USA
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. }
- unit grbtree;
- {$ifdef FPC}
- {$mode delphi}
- {$H+}
- {$endif FPC}
- {$TYPEDADDRESS ON}
- {$define RB_DEBUG}
- interface
- const
- HEIGHT_LIMIT = 64;
- type
- {KCOMP = class
- public
- // Return
- // * if A>B then 1
- // * if A=B then 0
- // * if A<B then -1
- class function Compare(const A, B : TRBTreeNodeData) : Integer;
- end; }
- TRBTree<T, KCOMP> = class
- public type
- TRBTreeNodeData = T;
- PRBTreeNode = ^TRBTreeNode;
- PRBTreeAllocator = ^TRBTreeAllocator;
- TRBTreeNode = record
- Links : array[Boolean] of PRBTreeNode;
- Data : TRBTreeNodeData;
- Red : Boolean;
- end;
- TRBTreeNodeCreator = function(AContext : Pointer) : PRBTreeNode;
- TRBTreeNodeDestructor = procedure(ANode : PRBTreeNode; AContext : Pointer);
- TRBTreeAllocator = record
- CreateNode : TRBTreeNodeCreator;
- FreeNode : TRBTreeNodeDestructor;
- end;
- TRBTreeNodeComparator = KCOMP;
- ThisType = TRBTree<T,KCOMP>;
- private type
- TBaseIterator = record
- Tree : ThisType;
- StartingNode : PRBTreeNode;
- StartingDir : Boolean;
- Current : PRBTreeNode;
- Top : NativeInt;
- Path : array[0..(HEIGHT_LIMIT-1)] of PRBTreeNode;
- end;
- PBaseIterator = ^TBaseIterator;
- public type
- TIterator = class
- private
- FHandle : PBaseIterator;
- FResetState : Boolean;
- private
- public
- constructor Create(AHandle : PBaseIterator);
- destructor Destroy;override;
- procedure Reset();
- function MoveNext() : Boolean;inline;
- function MovePrevious() : Boolean;inline;
- function GetCurrent : TRBTreeNodeData;inline;
- function GetCurrentNode : PRBTreeNode;inline;
- end;
- public var
- Root : PRBTreeNode;
- //FSize : Integer;
- Allocator : TRBTreeAllocator;
- Comparator : TRBTreeNodeComparator;
- private
- class function TreeCreateIterator() : PBaseIterator;static;inline;
- class procedure TreeFreeIterator(AItem : PBaseIterator);static;inline;
- class procedure TreeInitIterator(
- AIterator : PBaseIterator;
- const ATree : ThisType;
- const AStartingNode : PRBTreeNode;
- const ADirection : Boolean
- );static;
- class function TreeIteratorMove(
- AIterator : PBaseIterator;
- ADirection : Boolean
- ) : PRBTreeNode;static;
- class function TreeIteratorMoveNext(AIterator : PBaseIterator) : PRBTreeNode;static;inline;
- class function TreeIteratorMovePrevious(AIterator : PBaseIterator) : PRBTreeNode;static;inline;
- function CreateIterator(
- const ANode : PRBTreeNode;
- const ADirection : Boolean
- ) : TIterator;inline;
- private
- class function DefaultCreateNode(AContext : Pointer) : PRBTreeNode;static;
- class procedure DefaultFreeNode(ANode : PRBTreeNode; AContext : Pointer);static;
- function InitNode(ANode : PRBTreeNode; AData : TRBTreeNodeData) : PRBTreeNode;inline;
- function IsRed(ANode : PRBTreeNode): Boolean;inline;
- function RotateDouble(ARoot : PRBTreeNode; const ADir : Boolean) : PRBTreeNode;inline;
- function RotateSingle(ARoot : PRBTreeNode; const ADir : Boolean) : PRBTreeNode;
- public
- constructor Create(const AAllocator : PRBTreeAllocator);overload;
- constructor Create();overload;
- destructor Destroy;override;
- procedure Clear();
- function FindNode(const AData : TRBTreeNodeData) : PRBTreeNode;
- function Insert(const AData : TRBTreeNodeData) : PRBTreeNode;
- function Remove(const AData : TRBTreeNodeData) : Boolean;
- function CreateForwardIterator(const ANode : PRBTreeNode) : TIterator;overload;inline;
- function CreateForwardIterator() : TIterator;overload;inline;
- function CreateBackwardIterator(const ANode : PRBTreeNode) : TIterator;overload;inline;
- function CreateBackwardIterator() : TIterator;overload;inline;
- {$ifdef RB_DEBUG}
- function SelfAssert(ARoot : PRBTreeNode; var AErrorMessage : string) : Boolean;overload;
- function SelfAssert(var AErrorMessage : string) : Boolean;overload;
- {$endif RB_DEBUG}
- end;
- TOrdinalComparator<T> = class
- public type
- TOrdinalType = T;
- public
- // Return
- // * if A>B then 1
- // * if A=B then 0
- // * if A<B then -1
- class function Compare(const A, B : TOrdinalType) : Integer;static;inline;
- end;
- implementation
- { TRBTree<T> }
- function TRBTree<T,KCOMP>.IsRed(ANode : PRBTreeNode): Boolean;inline;
- begin
- Result := (ANode <> nil) and ANode^.Red;
- end;
- function TRBTree<T,KCOMP>.InitNode(ANode: PRBTreeNode; AData: TRBTreeNodeData): PRBTreeNode;inline;
- begin
- Result := ANode;
- Result^.Data := AData;
- Result^.Red := True;
- Result^.Links[False] := nil;
- Result^.Links[True] := nil;
- end;
- function TRBTree<T,KCOMP>.RotateDouble(ARoot: PRBTreeNode; const ADir: Boolean): PRBTreeNode;inline;
- begin
- ARoot^.Links[not ADir] := RotateSingle(ARoot^.Links[not ADir], not ADir );
- Result := RotateSingle(ARoot,ADir);
- end;
- function TRBTree<T,KCOMP>.RotateSingle(ARoot: PRBTreeNode; const ADir: Boolean): PRBTreeNode;
- var
- t : PRBTreeNode;
- begin
- t := ARoot^.Links[not ADir];
- ARoot^.Links[not ADir] := t^.Links[ADir];
- t^.Links[ADir] := ARoot;
- ARoot^.Red := True;
- t^.Red := False;
- Result := t;
- end;
- class function TRBTree<T,KCOMP>.TreeCreateIterator() : PBaseIterator;static;
- begin
- Result := AllocMem(SizeOf(TBaseIterator));
- end;
- class procedure TRBTree<T,KCOMP>.TreeFreeIterator(AItem : PBaseIterator);static;
- begin
- if (AItem <> nil) then
- FreeMem(AItem,SizeOf(AItem^));
- end;
- class procedure TRBTree<T,KCOMP>.TreeInitIterator(
- AIterator : PBaseIterator;
- const ATree : ThisType;
- const AStartingNode : PRBTreeNode;
- const ADirection : Boolean
- );static;
- begin
- AIterator^.Tree := ATree;
- AIterator^.StartingNode := AStartingNode;
- AIterator^.StartingDir := ADirection;
- if (AStartingNode = nil) then
- AIterator^.Current := AIterator^.Tree.Root
- else
- AIterator^.Current := AStartingNode;
- AIterator^.Top := 0;
- // Save the path for later traversal
- if (AIterator^.Current <> nil) then begin
- while (AIterator^.Current^.Links[ADirection] <> nil) do begin
- AIterator^.Path[AIterator^.Top] := AIterator^.Current;
- Inc(AIterator^.Top);
- AIterator^.Current := AIterator^.Current^.Links[ADirection];
- end;
- end;
- end;
- class function TRBTree<T,KCOMP>.TreeIteratorMove(
- AIterator : PBaseIterator;
- ADirection : Boolean
- ) : PRBTreeNode;static;
- var
- last : PRBTreeNode;
- begin
- Result := nil;
- if (AIterator^.Current = nil) then
- exit;
- if (AIterator^.Current^.Links[ADirection] <> nil) then begin
- // Continue down this branch
- AIterator^.Path[AIterator^.Top] := AIterator^.Current;
- Inc(AIterator^.Top);
- AIterator^.Current := AIterator^.Current^.Links[ADirection];
- while ( AIterator^.Current^.Links[not ADirection] <> nil) do begin
- AIterator^.Path[AIterator^.Top] := AIterator^.Current;
- Inc(AIterator^.Top);
- AIterator^.Current := AIterator^.Current^.Links[not ADirection];
- end;
- end else begin
- // Move to the next branch
- repeat
- if (AIterator^.Top = 0) then begin
- AIterator^.Current := nil;
- break;
- end;
- last := AIterator^.Current;
- Dec(AIterator^.Top);
- AIterator^.Current := AIterator^.Path[AIterator^.Top];
- until (last <> AIterator^.Current^.Links[ADirection]);
- end;
- Result := AIterator^.Current;
- end;
- class function TRBTree<T,KCOMP>.TreeIteratorMoveNext(
- AIterator : PBaseIterator
- ) : PRBTreeNode;static;
- begin
- Result := TreeIteratorMove(AIterator,True);
- end;
- class function TRBTree<T,KCOMP>.TreeIteratorMovePrevious(
- AIterator : PBaseIterator
- ) : PRBTreeNode;static;
- begin
- Result := TreeIteratorMove(AIterator,False);
- end;
- function TRBTree<T,KCOMP>.CreateIterator(
- const ANode : PRBTreeNode;
- const ADirection : Boolean
- ) : TIterator;
- var
- h : PBaseIterator;
- begin
- h := TreeCreateIterator();
- TreeInitIterator(h,Self,ANode,ADirection);
- Result := TIterator.Create(h);
- end;
- class function TRBTree<T,KCOMP>.DefaultCreateNode(AContext: Pointer): PRBTreeNode;
- begin
- New(Result);
- end;
- class procedure TRBTree<T,KCOMP>.DefaultFreeNode(ANode: PRBTreeNode; AContext: Pointer);
- begin
- Dispose(ANode);
- end;
- constructor TRBTree<T,KCOMP>.Create(const AAllocator : PRBTreeAllocator);
- begin
- Root := nil;
- Allocator := AAllocator^;
- //Comparator := TRBTreeNodeComparator.Create();
- end;
- constructor TRBTree < T, KCOMP > .Create();
- var
- a : TRBTreeAllocator;
- begin
- a.CreateNode := TRBTreeNodeCreator(DefaultCreateNode);
- a.FreeNode := TRBTreeNodeDestructor(DefaultFreeNode);
- Create(@a);
- end;
- destructor TRBTree<T,KCOMP>.Destroy;
- begin
- Clear();
- //Comparator.Free();
- inherited;
- end;
- procedure TRBTree<T,KCOMP>.Clear();
- var
- it, save : PRBTreeNode;
- begin
- it := Root;
- while (it <> nil) do begin
- if (it^.Links[False] <> nil) then begin
- // Right rotation
- save := it^.Links[False];
- it^.Links[False] := save^.Links[True];
- save^.Links[True] := it;
- end else begin
- save := it^.Links[True];
- Allocator.FreeNode(it,Self);
- end;
- it := save;
- end;
- end;
- function TRBTree<T,KCOMP>.FindNode(const AData: TRBTreeNodeData): PRBTreeNode;
- var
- it : PRBTreeNode;
- cp : TRBTreeNodeComparator;
- dir : Boolean;
- begin
- Result := nil;
- it := Root;
- if (it = nil) then
- exit;
- cp := Comparator;
- while (it <> nil) do begin
- if (cp.Compare(it^.Data,AData) = 0) then begin
- Result := it;
- Break;
- end;
- dir := (cp.Compare(it^.Data,AData) < 0);
- it := it^.Links[dir];
- end;
- end;
- function TRBTree<T,KCOMP>.Insert(const AData: TRBTreeNodeData): PRBTreeNode;
- var
- head : TRBTreeNode;
- g, t : PRBTreeNode; // Grandparent & parent
- p, q : PRBTreeNode; // Iterator & parent
- dir, last, dir2 : Boolean;
- cp : TRBTreeNodeComparator;
- begin
- if (Root = nil) then begin
- // Empty tree case
- Root := InitNode(Allocator.CreateNode(Self),AData);
- Result := Root;
- end else begin
- FillChar(head,SizeOf(head),0); // False tree root
- dir := False;
- last := False;
- // Set up helpers
- t := @head;
- g := nil;
- p := nil;
- t^.Links[True] := Root;
- q := t^.Links[True];
- // Search down the tree
- cp := Comparator;
- while True do begin
- if (q = nil) then begin
- // Insert new node at the bottom
- q := InitNode(Allocator.CreateNode(Self),AData);
- p^.Links[dir] := q;
- end else if IsRed(q^.Links[False]) and IsRed(q^.Links[True]) then begin
- // Color flip
- q^.Red := True;
- q^.Links[False]^.Red := False;
- q^.Links[True]^.Red := False;
- end;
- // Fix red violation
- if IsRed(q) and IsRed(p) then begin
- dir2 := (t^.Links[True] = g);
- if (q = p^.Links[last]) then
- t^.Links[dir2] := RotateSingle(g, not last)
- else
- t^.Links[dir2] := RotateDouble(g, not last );
- end;
- // Stop if found
- if (cp.Compare(q^.Data,AData) = 0) then begin
- Result := q;
- break;
- end;
- last := dir;
- dir := (cp.Compare(q^.Data,AData) < 0);
- // Update helpers
- if (g <> nil) then
- t := g;
- g := p;
- p := q;
- q := q^.Links[dir];
- end;
- // Update root
- Root := head.Links[True];
- end;
- // Make root black
- Root^.Red := False;
- end;
- function TRBTree<T,KCOMP>.Remove(const AData: TRBTreeNodeData): Boolean;
- var
- head : TRBTreeNode;
- q, p, g, f, s : PRBTreeNode;
- dir, last, dir2 : Boolean;
- cp : TRBTreeNodeComparator;
- begin
- Result := False;
- if (Root = nil) then
- exit;
- FillChar(head,SizeOf(head),0); // False tree root
- f := nil;
- dir := True;
- // Set up helpers
- q := @head;
- p := nil;
- g := nil;
- q^.Links[True] := Root;
- // Search and push a red down
- cp := Comparator;
- while (q^.Links[dir] <> nil) do begin
- last := dir;
- // Update helpers
- g := p;
- p := q;
- q := q^.Links[dir];
- dir := (cp.Compare(q^.Data,AData) < 0);
- // Save found node
- if (cp.Compare(q^.Data,AData) = 0) then
- f := q;
- // Push the red node down
- if not(IsRed(q)) and not(IsRed(q^.Links[dir])) then begin
- if IsRed(q^.Links[not dir]) then begin
- p^.Links[last] := RotateSingle(q,dir);
- p := p^.Links[last];
- end else if not IsRed(q^.Links[not dir]) then begin
- s := p^.Links[not last];
- if (s <> nil) then begin
- if not(IsRed(s^.Links[not last])) and not(IsRed(s^.Links[last])) then begin
- // Color flip
- p^.Red := False;
- s^.Red := True;
- q^.Red := True;
- end else begin
- dir2 := (g^.Links[True] = p);
- if IsRed(s^.Links[last]) then
- g^.Links[dir2] := RotateDouble(p,last)
- else if IsRed(s^.Links[not last]) then
- g^.Links[dir2] := RotateSingle(p,last);
- // Ensure correct coloring
- g^.Links[dir2]^.Red := True;
- q^.Red := g^.Links[dir2]^.Red;
- g^.Links[dir2]^.Links[False]^.Red := False;
- g^.Links[dir2]^.Links[True]^.Red := False;
- end;
- end;
- end;
- end;
- end;
- // Replace and remove if found
- if (f <> nil) then begin
- f^.Data := q^.Data;
- p^.Links[(p^.Links[True] = q)] :=
- q^.Links[(q^.Links[False] = nil)];
- Allocator.FreeNode(q,Self);
- Result := True;
- end;
- // Update root and make it black
- Root := head.Links[True];
- if (Root <> nil) then
- Root^.Red := False;
- end;
- function TRBTree<T,KCOMP>.CreateForwardIterator(const ANode : PRBTreeNode) : TIterator;
- begin
- Result := CreateIterator(ANode,False);
- end;
- function TRBTree<T,KCOMP>.CreateForwardIterator() : TIterator;
- begin
- Result := CreateForwardIterator(Root);
- end;
- function TRBTree<T,KCOMP>.CreateBackwardIterator(const ANode : PRBTreeNode) : TIterator;
- begin
- Result := CreateIterator(ANode,True);
- end;
- function TRBTree<T,KCOMP>.CreateBackwardIterator() : TIterator;
- begin
- Result := CreateBackwardIterator(Root);
- end;
- {$ifdef RB_DEBUG}
- function TRBTree<T,KCOMP>.SelfAssert(ARoot : PRBTreeNode; var AErrorMessage: string): Boolean;
- var
- lh, rh : Boolean;
- ln, rn : PRBTreeNode;
- e : string;
- begin
- AErrorMessage := '';
- if (ARoot = nil) then begin
- Result := True;
- exit;
- end;
- e := '';
- ln := ARoot^.Links[False];
- rn := ARoot^.Links[True];
- // Consecutive red links
- if IsRed(ARoot) then begin
- if IsRed(ln) or IsRed(rn) then begin
- AErrorMessage := 'Red violation';
- Result := False;
- exit;
- end;
- end;
- lh := SelfAssert(ln,e);
- AErrorMessage := AErrorMessage + ' ' + e;
- rh := SelfAssert(rn,e);
- AErrorMessage := AErrorMessage + ' ' + e;
- // Invalid binary search tree
- if ( ( (ln <> nil) and (Comparator.Compare(ln^.Data,ARoot^.Data) >= 0) ) or
- ( (rn <> nil) and (Comparator.Compare(rn^.Data,ARoot^.Data) <= 0) ) )
- then begin
- AErrorMessage := AErrorMessage + ' ' + 'Binary tree violation';
- Result := False;
- Exit;
- end;
- // Black height mismatch
- if ( lh and rh and (lh <> rh) ) then begin
- AErrorMessage := AErrorMessage + ' ' + 'Black violation';
- Result := False;
- Exit;
- end;
- Result := lh and rh;
- end;
- function TRBTree<T,KCOMP>.SelfAssert(var AErrorMessage: string): Boolean;
- begin
- Result := Self.SelfAssert(Root, AErrorMessage);
- end;
- {$endif RB_DEBUG}
- constructor TRBTree<T,KCOMP>.TIterator.Create(AHandle : PBaseIterator);
- begin
- inherited Create();
- FHandle := AHandle;
- FResetState := True;
- end;
- destructor TRBTree<T,KCOMP>.TIterator.Destroy();
- begin
- TreeFreeIterator(FHandle);
- inherited Destroy;
- end;
- function TRBTree<T,KCOMP>.TIterator.MoveNext : Boolean;
- begin
- if FResetState then begin
- FResetState := False;
- Result := (FHandle^.Current <> nil);
- exit;
- end;
- Result := (TreeIteratorMoveNext(FHandle) <> nil);
- end;
- function TRBTree<T,KCOMP>.TIterator.MovePrevious : Boolean;
- begin
- if FResetState then begin
- FResetState := False;
- Result := (FHandle^.Current <> nil);
- exit;
- end;
- Result := (TreeIteratorMovePrevious(FHandle) <> nil);
- end;
- function TRBTree<T,KCOMP>.TIterator.GetCurrent : TRBTreeNodeData;
- begin
- Result := GetCurrentNode()^.Data;
- end;
- function TRBTree<T,KCOMP>.TIterator.GetCurrentNode : PRBTreeNode;
- begin
- Result := FHandle^.Current;
- end;
- procedure TRBTree<T,KCOMP>.TIterator.Reset();
- begin
- FResetState := True;
- TreeInitIterator(FHandle,FHandle^.Tree,FHandle^.StartingNode,FHandle^.StartingDir)
- end;
- { TOrdinalComparator<T> }
- class function TOrdinalComparator<T>.Compare(const A, B: TOrdinalType): Integer;
- begin
- if (A = B) then
- exit(0);
- if (A > B) then
- exit(1);
- exit(-1);
- end;
- end.
|