1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
|
{
*****************************************************************************
This file is part of LazUtils.
See the file COPYING.modifiedLGPL.txt, included in this distribution,
for details about the license.
*****************************************************************************
Authors: Mattias Gaertner, Jeroen van Iddekinge
Abstract:
Defines the simple double connected queue TLinkList.
It supports Adding, Deleting, getting First and getting Last in O(1).
Finding can be done in time O(n).
}
unit LazLinkedList;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
type
TLinkListItem = class
Next : TLinkListItem;
Prior : TLinkListItem;
procedure ResetItem; virtual;
end;
TLinkList = class
private
FFirstFree: TLinkListItem;
FFreeCount: integer;
FFirst: TLinkListItem;
FLast: TLinkListItem;
FCount: integer;
procedure DisposeItem(AnItem: TLinkListItem);
procedure Unbind(AnItem: TLinkListItem);
protected
function CreateItem: TLinkListItem; virtual; abstract;
function GetNewItem: TLinkListItem;
procedure AddAsLast(AnItem: TLinkListItem);
public
property First: TLinkListItem read FFirst;
property Last: TLinkListItem read FLast;
property Count: integer read FCount;
procedure Delete(AnItem: TLinkListItem);
procedure MoveToLast(AnItem: TLinkListItem);
procedure Clear;
function ConsistencyCheck: integer;
constructor Create;
destructor Destroy; override;
end;
implementation
{ TLinkList }
procedure TLinkListItem.ResetItem;
begin
Next := nil;
Prior := nil;
end;
constructor TLinkList.Create;
begin
inherited Create;
end;
destructor TLinkList.Destroy;
var AnItem: TLinkListItem;
begin
Clear;
// clear the free list
while FFirstFree<>nil do begin
AnItem:=FFirstFree;
FFirstFree:=AnItem.Next;
AnItem.Destroy;
end;
inherited Destroy;
end;
procedure TLinkList.Delete(AnItem: TLinkListItem);
begin
if AnItem=nil then exit;
Unbind(AnItem);
AnItem.Destroy;
end;
procedure TLinkList.MoveToLast(AnItem: TLinkListItem);
begin
if AnItem=nil then exit;
Unbind(AnItem);
AddAsLast(AnItem);
end;
procedure TLinkList.Clear;
begin
while First<>nil do Delete(First);
end;
function TLinkList.GetNewItem: TLinkListItem;
begin
if FFirstFree<>nil then begin
Result:=FFirstFree;
FFirstFree:=FFirstFree.Next;
if FFirstFree<>nil then
FFirstFree.Prior:=nil;
dec(FFreeCount);
end else begin
Result := CreateItem;
end;
Result.Next:=nil;
Result.Prior:=nil;
end;
procedure TLinkList.DisposeItem(AnItem: TLinkListItem);
var i: integer;
begin
if FFreeCount<=2*FCount then begin
AnItem.ResetItem;
AnItem.Next:=FFirstFree;
FFirstFree:=AnItem;
if AnItem.Next<>nil then AnItem.Next.Prior:=AnItem;
inc(FFreeCount);
end else begin
AnItem.Destroy;
if (FCount+5)<2*FFreeCount then begin
for i:=1 to 2 do begin
if FFirstFree<>nil then begin
AnItem:=FFirstFree;
FFirstFree:=FFirstFree.Next;
if FFirstFree<>nil then
FFirstFree.Prior:=nil;
AnItem.Destroy;
dec(FFreeCount);
end;
end;
end;
end;
end;
procedure TLinkList.Unbind(AnItem: TLinkListItem);
begin
if AnItem=nil then exit;
if FFirst=AnItem then FFirst:=FFirst.Next;
if FLast=AnItem then FLast:=FLast.Prior;
if AnItem.Prior<>nil then AnItem.Prior.Next:=AnItem.Next;
if AnItem.Next<>nil then AnItem.Next.Prior:=AnItem.Prior;
AnItem.Prior:=nil;
AnItem.Next:=nil;
dec(FCount);
end;
procedure TLinkList.AddAsLast(AnItem: TLinkListItem);
begin
AnItem.Prior:=FLast;
AnItem.Next:=nil;
FLast:=AnItem;
if AnItem.Prior<>nil then
AnItem.Prior.Next:=AnItem
else
FFirst:=AnItem;
inc(FCount);
end;
function TLinkList.ConsistencyCheck: integer;
var RealCount: integer;
AnItem: TLinkListItem;
begin
// test free list
RealCount:=0;
AnItem:=FFirstFree;
while AnItem<>nil do begin
inc(RealCount);
AnItem:=AnItem.Next;
end;
if FFreeCount<>RealCount then begin
Result:=-1; exit;
end;
// test items
RealCount:=0;
AnItem:=FFirst;
while AnItem<>nil do begin
if (AnItem.Next<>nil) and (AnItem.Next.Prior<>AnItem) then begin
Result:=-2; exit;
end;
if (AnItem.Prior<>nil) and (AnItem.Prior.Next<>AnItem) then begin
Result:=-3; exit;
end;
inc(RealCount);
AnItem:=AnItem.Next;
end;
if FCount<>RealCount then begin
Result:=-4; exit;
end;
Result:=0;
end;
end.
|