{ 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 = 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; 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 = class public type TOrdinalType = T; public // Return // * if A>B then 1 // * if A=B then 0 // * if A } function TRBTree.IsRed(ANode : PRBTreeNode): Boolean;inline; begin Result := (ANode <> nil) and ANode^.Red; end; function TRBTree.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.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.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.TreeCreateIterator() : PBaseIterator;static; begin Result := AllocMem(SizeOf(TBaseIterator)); end; class procedure TRBTree.TreeFreeIterator(AItem : PBaseIterator);static; begin if (AItem <> nil) then FreeMem(AItem,SizeOf(AItem^)); end; class procedure TRBTree.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.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.TreeIteratorMoveNext( AIterator : PBaseIterator ) : PRBTreeNode;static; begin Result := TreeIteratorMove(AIterator,True); end; class function TRBTree.TreeIteratorMovePrevious( AIterator : PBaseIterator ) : PRBTreeNode;static; begin Result := TreeIteratorMove(AIterator,False); end; function TRBTree.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.DefaultCreateNode(AContext: Pointer): PRBTreeNode; begin New(Result); end; class procedure TRBTree.DefaultFreeNode(ANode: PRBTreeNode; AContext: Pointer); begin Dispose(ANode); end; constructor TRBTree.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.Destroy; begin Clear(); //Comparator.Free(); inherited; end; procedure TRBTree.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.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.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.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.CreateForwardIterator(const ANode : PRBTreeNode) : TIterator; begin Result := CreateIterator(ANode,False); end; function TRBTree.CreateForwardIterator() : TIterator; begin Result := CreateForwardIterator(Root); end; function TRBTree.CreateBackwardIterator(const ANode : PRBTreeNode) : TIterator; begin Result := CreateIterator(ANode,True); end; function TRBTree.CreateBackwardIterator() : TIterator; begin Result := CreateBackwardIterator(Root); end; {$ifdef RB_DEBUG} function TRBTree.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.SelfAssert(var AErrorMessage: string): Boolean; begin Result := Self.SelfAssert(Root, AErrorMessage); end; {$endif RB_DEBUG} constructor TRBTree.TIterator.Create(AHandle : PBaseIterator); begin inherited Create(); FHandle := AHandle; FResetState := True; end; destructor TRBTree.TIterator.Destroy(); begin TreeFreeIterator(FHandle); inherited Destroy; end; function TRBTree.TIterator.MoveNext : Boolean; begin if FResetState then begin FResetState := False; Result := (FHandle^.Current <> nil); exit; end; Result := (TreeIteratorMoveNext(FHandle) <> nil); end; function TRBTree.TIterator.MovePrevious : Boolean; begin if FResetState then begin FResetState := False; Result := (FHandle^.Current <> nil); exit; end; Result := (TreeIteratorMovePrevious(FHandle) <> nil); end; function TRBTree.TIterator.GetCurrent : TRBTreeNodeData; begin Result := GetCurrentNode()^.Data; end; function TRBTree.TIterator.GetCurrentNode : PRBTreeNode; begin Result := FHandle^.Current; end; procedure TRBTree.TIterator.Reset(); begin FResetState := True; TreeInitIterator(FHandle,FHandle^.Tree,FHandle^.StartingNode,FHandle^.StartingDir) end; { TOrdinalComparator } class function TOrdinalComparator.Compare(const A, B: TOrdinalType): Integer; begin if (A = B) then exit(0); if (A > B) then exit(1); exit(-1); end; end.