| 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}interfaceconst  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.
 |