📄 sttree.pas
字号:
Found := True;
end else begin
with Stack[StackP] do begin
Node := P;
Comparison := CmpRes;
end;
P := P.tnPos[CmpRes > 0];
if not Assigned(P) then
{Node to delete not found}
Exit;
end;
end;
{Delete the node found}
Q := P;
if (not Assigned(Q.tnPos[Right])) or (not Assigned(Q.tnPos[Left])) then begin
{Node has at most one branch}
Dec(StackP);
P := Q.tnPos[Assigned(Q.tnPos[Right])];
if StackP = 0 then
trRoot := P
else with Stack[StackP] do
Node.tnPos[Comparison > 0] := P;
end else begin
{Node has two branches; stack nodes to reach one with no right child}
P := Q.tnPos[Left];
while Assigned(P.tnPos[Right]) do begin
Inc(StackP);
with Stack[StackP] do begin
Node := P;
Comparison := 1;
end;
P := P.tnPos[Right];
end;
{Swap the node to delete with the terminal node}
TmpData := Q.Data;
Q.Data := P.Data;
Q := P;
with Stack[StackP] do begin
Node.tnPos[Comparison > 0].Data := TmpData;
Node.tnPos[Comparison > 0] := P.tnPos[Left];
end;
end;
{Dispose of the deleted node}
DisposeNodeData(Q);
Q.Free;
Dec(FCount);
{Unwind the stack and rebalance}
SubTreeDec := True;
while (StackP > 0) and SubTreeDec do begin
if StackP = 1 then
DelBalance(trRoot, SubTreeDec, Stack[1].Comparison)
else with Stack[StackP-1] do
DelBalance(Node.tnPos[Comparison > 0], SubTreeDec, Stack[StackP].Comparison);
dec(StackP);
end;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
function TStTree.Find(Data : Pointer) : TStTreeNode;
var
P : TStTreeNode;
CmpRes : Integer;
begin
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
P := trRoot;
while Assigned(P) do begin
CmpRes := DoCompare(Data, P.Data);
if CmpRes = 0 then begin
Result := P;
Exit;
end else
P := P.tnPos[CmpRes > 0];
end;
Result := nil;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
function TStTree.First : TStTreeNode;
begin
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
if Count = 0 then
Result := nil
else begin
Result := trRoot;
while Assigned(Result.tnPos[Left]) do
Result := Result.tnPos[Left];
end;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
function TStTree.Insert(Data : Pointer) : TStTreeNode;
begin
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
{Create the node}
Result := TStTreeNode(conNodeClass.Create(Data));
trInsertNode(Result);
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
function TStTree.Iterate(Action : TIterateFunc; Up : Boolean;
OtherData : Pointer) : TStTreeNode;
var
P : TStTreeNode;
Q : TStTreeNode;
StackP : Integer;
Stack : StackArray;
begin
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
StackP := 0;
P := trRoot;
repeat
while Assigned(P) do begin
Inc(StackP);
Stack[StackP].Node := P;
P := P.tnPos[not Up];
end;
if StackP = 0 then begin
Result := nil;
Exit;
end;
P := Stack[StackP].Node;
Dec(StackP);
Q := P;
P := P.tnPos[Up];
if not Action(Self, Q, OtherData) then begin
Result := Q;
Exit;
end;
until False;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
procedure TStTree.Join(T: TStTree; IgnoreDups : Boolean);
begin
{$IFDEF ThreadSafe}
EnterClassCS;
EnterCS;
T.EnterCS;
try
{$ENDIF}
trIgnoreDups := IgnoreDups;
T.Iterate(JoinNode, True, Self);
T.IncNodeProtection;
T.Free;
{$IFDEF ThreadSafe}
finally
T.LeaveCS;
LeaveCS;
LeaveClassCS;
end;
{$ENDIF}
end;
function TStTree.Last : TStTreeNode;
begin
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
if Count = 0 then
Result := nil
else begin
Result := trRoot;
while Assigned(Result.tnPos[Right]) do
Result := Result.tnPos[Right];
end;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
function TStTree.Next(N : TStTreeNode) : TStTreeNode;
var
Found : Word;
P : TStTreeNode;
StackP : Integer;
Stack : StackArray;
begin
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
Result := nil;
Found := 0;
StackP := 0;
P := trRoot;
repeat
while Assigned(P) do begin
Inc(StackP);
Stack[StackP].Node := P;
P := P.tnPos[Left];
end;
if StackP = 0 then
Exit;
P := Stack[StackP].Node;
Dec(StackP);
if Found = 1 then begin
Result := P;
Exit;
end;
if P = N then
Inc(Found);
P := P.tnPos[Right];
until False;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
function TStTree.Prev(N : TStTreeNode) : TStTreeNode;
var
Found : Word;
P : TStTreeNode;
StackP : Integer;
Stack : StackArray;
begin
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
Result := nil;
Found := 0;
StackP := 0;
P := trRoot;
repeat
while Assigned(P) do begin
Inc(StackP);
Stack[StackP].Node := P;
P := P.tnPos[Right];
end;
if StackP = 0 then
Exit;
P := Stack[StackP].Node;
Dec(StackP);
if Found = 1 then begin
Result := P;
Exit;
end;
if P = N then
Inc(Found);
P := P.tnPos[Left];
until False;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
function TStTree.Split(Data : Pointer) : TStTree;
var
SR : SplitRec;
begin
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
{Create and initialize the new tree}
Result := TStTreeClass(ClassType).Create(conNodeClass);
Result.Compare := Compare;
Result.OnCompare := OnCompare;
Result.DisposeData := DisposeData;
Result.OnDisposeData := OnDisposeData;
{Scan all elements to transfer some to new tree}
SR.SData := Data;
SR.STree := Result;
{Prevent SplitTree from disposing of node data it moves from old tree to new}
DisposeData := nil;
OnDisposeData := nil;
Iterate(SplitTree, True, @SR);
{Restore DisposeData property}
DisposeData := Result.DisposeData;
OnDisposeData := Result.OnDisposeData;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
procedure TStTree.trInsertNode(N : TStTreeNode);
var
P : TStTreeNode;
CmpRes : Integer;
StackP : Integer;
Stack : StackArray;
SubTreeInc : Boolean;
begin
if not Assigned(N) then
Exit;
{Handle first node}
P := trRoot;
if not Assigned(P) then begin
trRoot := N;
Inc(FCount);
Exit;
end;
{Find where new node should fit in tree}
StackP := 0;
CmpRes := 0; {prevent D32 from generating a warning}
while Assigned(P) do begin
CmpRes := DoCompare(N.Data, P.Data);
if CmpRes = 0 then begin
{New node matches a node already in the tree, free it}
N.Free;
RaiseContainerError(stscDupNode);
end;
Inc(StackP);
with Stack[StackP] do begin
Node := P;
Comparison := CmpRes;
end;
P := P.tnPos[CmpRes > 0];
end;
{Insert new node}
Stack[StackP].Node.tnPos[CmpRes > 0] := N;
Inc(FCount);
{Unwind the stack and rebalance}
SubTreeInc := True;
while (StackP > 0) and SubTreeInc do begin
if StackP = 1 then
InsBalance(trRoot, SubTreeInc, Stack[1].Comparison)
else with Stack[StackP-1] do
InsBalance(Node.tnPos[Comparison > 0], SubTreeInc, Stack[StackP].Comparison);
dec(StackP);
end;
end;
procedure TStTree.LoadFromStream(S : TStream);
var
Data : pointer;
Reader : TReader;
StreamedClass : TPersistentClass;
StreamedNodeClass : TPersistentClass;
StreamedClassName : string;
StreamedNodeClassName : string;
begin
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
Clear;
Reader := TReader.Create(S, 1024);
try
with Reader do
begin
StreamedClassName := ReadString;
StreamedClass := GetClass(StreamedClassName);
if (StreamedClass = nil) then
RaiseContainerErrorFmt(stscUnknownClass, [StreamedClassName]);
if (not IsOrInheritsFrom(StreamedClass, Self.ClassType)) or
(not IsOrInheritsFrom(TStTree, StreamedClass)) then
RaiseContainerError(stscWrongClass);
StreamedNodeClassName := ReadString;
StreamedNodeClass := GetClass(StreamedNodeClassName);
if (StreamedNodeClass = nil) then
RaiseContainerErrorFmt(stscUnknownNodeClass, [StreamedNodeClassName]);
if (not IsOrInheritsFrom(StreamedNodeClass, conNodeClass)) or
(not IsOrInheritsFrom(TStTreeNode, StreamedNodeClass)) then
RaiseContainerError(stscWrongNodeClass);
ReadListBegin;
while not EndOfList do
begin
Data := DoLoadData(Reader);
Insert(Data);
end;
ReadListEnd;
end;
finally
Reader.Free;
end;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
procedure TStTree.StoreToStream(S : TStream);
var
Writer : TWriter;
StoreInfo : TStoreInfo;
begin
{$IFDEF ThreadSafe}
EnterCS;
try
{$ENDIF}
Writer := TWriter.Create(S, 1024);
try
with Writer do begin
WriteString(Self.ClassName);
WriteString(conNodeClass.ClassName);
WriteListBegin;
StoreInfo.Wtr := Writer;
StoreInfo.SDP := StoreData;
Iterate(StoreNode, false, @StoreInfo);
WriteListEnd;
end;
finally
Writer.Free;
end;
{$IFDEF ThreadSafe}
finally
LeaveCS;
end;
{$ENDIF}
end;
{$IFDEF ThreadSafe}
initialization
Windows.InitializeCriticalSection(ClassCritSect);
finalization
Windows.DeleteCriticalSection(ClassCritSect);
{$ENDIF}
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -