⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ezdslskp.pas

📁 Eazy Data Structures library for Delphi.
💻 PAS
📖 第 1 页 / 共 2 页
字号:
{===EZDSLSKP==========================================================

Part of the Delphi Structures Library--the skip list.

EZDSLSKP is Copyright (c) 1993-2002 by  Julian M. Bucknall

VERSION HISTORY
12Feb02 JMB 3.03 Release for Delphi 6
24Oct99 JMB 3.02 Release for Delphi 4 & 5
19Apr98 JMB 3.00 Major new version, release for Delphi 3
13Mar96 JMB 2.00 release for Delphi 2.0
12Nov95 JMB 1.01 fixed Iterate bug
18Jun95 JMB 1.00 conversion of EZStrucs to Delphi
=====================================================================}
{ Copyright (c) 1993-2002, Julian M. Bucknall. All Rights Reserved   }

unit EzdslSkp;

{$I EzdslDef.inc}
{---Place any compiler options you require here----------------------}


{--------------------------------------------------------------------}
{$I EzdslOpt.inc}

interface

uses
  SysUtils,
  {$IFDEF Windows}
  WinTypes,
  WinProcs,
  {$ENDIF}
  {$IFDEF Win32}
  Windows,
  {$ENDIF}
  {$IFDEF Linux}
  Types,
  Libc,
  {$ENDIF}
  Classes,
  {$IFDEF ThreadsExist}
  EzdslThd,
  {$ENDIF}
  EzdslCts,
  EzdslBse,
  EzdslSup,
  EzdslRnd;

type
  TSkipList = class(TAbstractContainer)
    {-Skip linked list object}
    private
      skBF, skAL  : PNode;
      skCurLevels : integer;
      skRandGen   : TEZRandomGenerator;
      skNewNodeLevel : integer;

    protected
      procedure acDisposeNode(aNode : PNode); override;
      function acNewNode(aData : pointer) : PNode; override;

      procedure acSort; override;

      function skCloneItem(SL : TAbstractContainer;
                           aData : pointer;
                           NSL : pointer) : boolean;
      function skMergeLists(aBeforeNode1 : PNode; aCount1 : longint;
                            aBeforeNode2 : PNode; aCount2 : longint) : PNode;
      function skMergeSort(aBeforeNode : PNode; aCount : longint) : PNode;

    public
      constructor Create(DataOwner : boolean); override;
      constructor Clone(Source : TAbstractContainer;
                        DataOwner : boolean; NewCompare : TCompareFunc); override;
      destructor Destroy; override;

      function Delete(Cursor : TListCursor) : TListCursor;
      procedure Empty; override;
      function Erase(Cursor : TListCursor) : TListCursor;
      function Examine(Cursor : TListCursor) : pointer;
      procedure Insert(var Cursor : TListCursor; aData : pointer);
      function IsAfterLast(Cursor : TListCursor) : boolean;
      function IsBeforeFirst(Cursor : TListCursor) : boolean;
      function Iterate(Action : TIterator; Backwards : boolean;
                        ExtraData : pointer) : pointer;
      procedure Join(List : TSkipList);
      function Next(Cursor : TListCursor) : TListCursor;
      function Prev(Cursor : TListCursor) : TListCursor;
      function Replace(Cursor : TListCursor; aData : pointer) : pointer;
      function Search(var Cursor : TListCursor; aData : pointer) : boolean;
      function SetBeforeFirst : TListCursor;
      function SetAfterLast : TListCursor;
      function Split(Cursor : TListCursor) : TSkipList;
  end;

{$IFDEF ThreadsExist}
type
  TThreadsafeSkipList = class
    protected {private}
      slSkipList : TSkipList;
      slResLock  : TezResourceLock;
    protected
    public
      constructor Create(aDataOwner : boolean);
      destructor Destroy; override;

      function AcquireAccess : TSkipList;
      procedure ReleaseAccess;
  end;
{$ENDIF}

implementation

{-An iterator for cloning a skip list}
function SkipListCloneItem(SL : TAbstractContainer;
                           aData : pointer;
                           NSL : pointer) : boolean; far;
var
  NewList : TSkipList absolute NSL;
  NewData : pointer;
  Dummy   : TListCursor;
begin
  Result := true;
  with NewList do begin
    if IsDataOwner then
      NewData := DupData(aData)
    else
      NewData := aData;
    try
      Insert(Dummy, NewData);
    except
      if IsDataOwner and Assigned(NewData) then
        DisposeData(NewData);
      raise;
    end;{try..except}
  end;
end;

{=TSkipList===========================================================
A skip linked list

This is a special type of linked list of data objects. Compared with
TList and TDList, this implementation uses nodes of varying sizes. The
nodes have between 1 and 16 (skMaxLevels) of forward pointers, the
higher ones skipping over nodes with less forward pointers. This means
much faster search times, but slightly slower list update times (ie
insert and delete). Can cope with searching long lists without too
much degradation. Compared with a red-black binary search tree, this
type of data structure will consume more memory, will have faster
insert times, slower (?) delete times, and will have comparable
(amortised) search times.

Reference
  Scheiner: Skip Lists (DDJ January 1994)
=====================================================================}
constructor TSkipList.Create(DataOwner : boolean);
var
  Level : integer;
begin
  {Note: we cannot use a NodeStore as the nodes have different
         sizes, so set NodeSize to 0.}
  acNodeSize := 0;
  inherited Create(DataOwner);
  skRandGen := TEZRandomGenerator.Create;
  skRandGen.SetSeed(0);
  skNewNodeLevel := skMaxLevels;
  skBF := acNewNode(nil);
  acCount := 0;
  skNewNodeLevel := 1;
  skAL := acNewNode(nil);
  acCount := 0;
  for Level := 0 to pred(skMaxLevels) do
    skBF^.FwLink[Level] := skAL;
  skBF^.BkLink:= skBF;
  skAL^.FwLink[0] := skAL;
  skAL^.BkLink:= skBF;
  skCurLevels := 1;
  acIsSorted := true; {and this cannot be changed}
end;
{--------}
constructor TSkipList.Clone(Source : TAbstractContainer;
                            DataOwner : boolean;
                            NewCompare : TCompareFunc);
var
  OldList : TSkipList absolute Source;
begin
  Create(DataOwner);
  Compare := NewCompare;
  DupData := OldList.DupData;
  DisposeData := OldList.DisposeData;

  if not (Source is TSkipList) then
    RaiseError(escBadSource);

  if not OldList.IsEmpty then
    OldList.Iterate(SkipListCloneItem, false, Self);
end;
{--------}
destructor TSkipList.Destroy;
begin
  skRandGen.Free;
  inherited Destroy;
end;
{--------}
procedure TSkipList.acDisposeNode(aNode : PNode);
begin
  {$IFDEF DEBUG}
  EZAssert(Assigned(aNode), ascFreeNilNode);
  {$ENDIF}
  SafeFreeMem(aNode, aNode^.Size);
  if (acCount > 0) then
    dec(acCount);
end;
{--------}
function TSkipList.acNewNode(aData : pointer) : PNode;
var
  NodeBytes : integer;
begin
  {Note: we must override the default node allocation as the nodes
         vary in size. The object variable skNewNodeLevel is the
         number of forward links we must reserve.}
  {$IFDEF DEBUG}
  EZAssert((0 < skNewNodeLevel) and (skNewNodeLevel <= skMaxLevels), ascBadSkipLevel);
  {$ENDIF}
  {Note: the formula below translates to this table of node sizes
     SkipLevel:  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16
    NodeSize16: 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76
    NodeSize32: 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 }
  NodeBytes := ((skNewNodeLevel+2) * sizeof(pointer)) + (sizeof(integer) * 2);
  SafeGetMem(Result, NodeBytes);
  with Result^ do begin
    Data := aData;
    Size := NodeBytes;
    Lvls := skNewNodeLevel;
  end;
  inc(acCount);
end;
{--------}
procedure TSkipList.acSort;
var
  i : integer;
  Dad, Son : PNode;
  PrevNodeAtLevel : array [0..pred(skMaxLevels)] of PNode;
begin
  {mergesort the linked list as a singly linked list}
  skMergeSort(skBF, Count);
  {now patch up the remaining forward links (ie, everything but
   forward link 0) and the back links}
  for i := 0 to pred(skMaxLevels) do
    PrevNodeAtLevel[i] := skBF;
  Son := skBF;
  while (Son <> skAL) do begin
    Dad := Son;
    Son := Dad^.FwLink[0];
    Son^.BkLink := Dad;
    for i := pred(Son^.Lvls) downto 1 do begin
      PrevNodeAtLevel[i]^.FwLink[i] := Son;
      PrevNodeAtLevel[i] := Son;
    end;
  end;
  {now tie up any loose ends by pointing the remaining forward links
   to the AfterLast node}
  for i := pred(skMaxLevels) downto 1 do
    PrevNodeAtLevel[i]^.FwLink[i] := skAL;
end;
{--------}
function TSkipList.Delete(Cursor : TListCursor) : TListCursor;
var
  aData     : pointer;
  Walker    : PNode;
  NextStep  : TListCursor;
  TempNode  : PNode;
  Level     : integer;
  CompResult: integer;
  PrevLink  : array [0..pred(skMaxLevels)] of PNode;
begin
  {$IFDEF DEBUG}
  EZAssert((not IsBeforeFirst(Cursor)) and (not IsAfterLast(Cursor)), ascDeleteEdges);
  {$ENDIF}
  aData := Examine(Cursor);
  Walker := PNode(SetBeforeFirst);
  {note: the following for loop is executed at least once
         because skCurLevels >= 1}
  for Level := pred(skCurLevels) downto 0 do begin
    NextStep := TListCursor(Walker^.FwLink[Level]);
    if IsAfterLast(NextStep) then
      CompResult := -1
    else
      CompResult := Compare(aData, Examine(NextStep));
    while (CompResult > 0) do begin
      Walker := PNode(NextStep);
      NextStep := TListCursor(Walker^.FwLink[Level]);
      if IsAfterLast(NextStep) then
        CompResult := -1
      else
        CompResult := Compare(aData, Examine(NextStep));
    end;
    PrevLink[Level] := Walker;
  end;
  with PNode(Cursor)^ do begin
    TempNode := FwLink[0];
    TempNode^.BkLink := BkLink;
    PrevLink[0]^.FwLink[0] := FwLink[0];
    for Level := 1 to pred(Lvls) do
      PrevLink[Level]^.FwLink[Level] := FwLink[Level];
  end;
  acDisposeNode(PNode(Cursor));
  Result := TListCursor(TempNode);
end;
{--------}
procedure TSkipList.Empty;
var
  Temp,
  Cursor : TListCursor;
  Level  : integer;
begin
  {Note: it will be faster to delete nodes from first principles
         rather than repeatedly call the Erase method.}
  if not IsEmpty then begin
    Cursor := Next(SetBeforeFirst);
    while not IsAfterLast(Cursor) do begin
      Temp := Cursor;
      Cursor := Next(Cursor);
      if IsDataOwner then
        DisposeData(Examine(Temp));
      acDisposeNode(PNode(Temp));
    end;
  end;
  if acInDone then begin
    if Assigned(skBF) then
      acDisposeNode(skBF);
    if Assigned(skAL) then
      acDisposeNode(skAL);
  end
  else begin
    {patch everything up again}
    for Level := 0 to pred(skMaxLevels) do
      skBF^.FwLink[Level] := skAL;
    skAL^.BkLink:= skBF;
    skCurLevels := 1;
    acCount := 0;
  end;
end;
{--------}
function TSkipList.Erase(Cursor : TListCursor) : TListCursor;
var
  Data : pointer;
begin
  {Note: Delete requires the Data field so dispose the data
         afterwards}
  Data := Examine(Cursor);
  Result := Delete(Cursor);
  if IsDataOwner then
    DisposeData(Data);
end;
{--------}
function TSkipList.Examine(Cursor : TListCursor) : pointer;
begin
  {$IFDEF DEBUG}
  EZAssert((not IsBeforeFirst(Cursor)) and (not IsAfterLast(Cursor)), ascExamineEdges);
  {$ENDIF}
  Result := PNode(Cursor)^.Data;
end;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -