Skip to content

Commit 59cac77

Browse files
authored
Add Depth First Search in Pascal (TheRenegadeCoder#4805)
1 parent 9e6f7ea commit 59cac77

File tree

1 file changed

+242
-0
lines changed

1 file changed

+242
-0
lines changed
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
program DepthFirstSearch;
2+
3+
{$mode objfpc}{$H+}
4+
5+
uses
6+
Classes,
7+
Generics.Collections,
8+
Sysutils;
9+
10+
type
11+
TIntegerList = specialize TList<integer>;
12+
TIntegerSet = specialize THashSet<integer>;
13+
TIntegerStack = specialize TStack<integer>;
14+
15+
TNode = class
16+
private
17+
FChildSet: TIntegerSet;
18+
public
19+
Id: integer;
20+
Children: TIntegerList;
21+
constructor Create(AId: integer);
22+
destructor Destroy; override;
23+
procedure AddChild(ChildId: integer);
24+
end;
25+
26+
TNodeDictionary = specialize TDictionary<integer, TNode>;
27+
28+
{ TTree }
29+
30+
TTree = class
31+
private
32+
function ContainsNode(NodeId: integer): boolean;
33+
public
34+
RootId: integer;
35+
Nodes: TNodeDictionary;
36+
constructor Create(ARootId: integer);
37+
destructor Destroy; override;
38+
procedure AddNode(Node: TNode);
39+
function GetNode(NodeId: integer): TNode;
40+
end;
41+
42+
procedure ShowUsage;
43+
begin
44+
Writeln('Usage: please provide a tree in an adjacency matrix form ("0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0") together with a list of vertex values ("1, 3, 5, 2, 4") and the integer to find ("4")');
45+
Halt(1);
46+
end;
47+
48+
{ TNode }
49+
50+
constructor TNode.Create(AId: integer);
51+
begin
52+
Id := AId;
53+
Children := TIntegerList.Create;
54+
FChildSet := TIntegerSet.Create;
55+
end;
56+
57+
destructor TNode.Destroy;
58+
begin
59+
Children.Free;
60+
FChildSet.Free;
61+
inherited;
62+
end;
63+
64+
procedure TNode.AddChild(ChildId: integer); inline;
65+
begin
66+
if FChildSet.Add(ChildId) then
67+
Children.Add(ChildId);
68+
end;
69+
70+
{ TTree }
71+
72+
constructor TTree.Create(ARootId: integer);
73+
begin
74+
RootId := ARootId;
75+
Nodes := TNodeDictionary.Create;
76+
end;
77+
78+
destructor TTree.Destroy;
79+
var
80+
Node: TNode;
81+
begin
82+
for Node in Nodes.Values do
83+
Node.Free;
84+
Nodes.Free;
85+
inherited;
86+
end;
87+
88+
procedure TTree.AddNode(Node: TNode); inline;
89+
begin
90+
Nodes.AddOrSetValue(Node.Id, Node);
91+
end;
92+
93+
// Retrieves a node by ID, or returns nil if not found
94+
function TTree.GetNode(NodeId: integer): TNode; inline;
95+
begin
96+
if not Nodes.TryGetValue(NodeId, Result) then
97+
Result := nil;
98+
end;
99+
100+
function TTree.ContainsNode(NodeId: integer): boolean; inline;
101+
begin
102+
Result := Nodes.ContainsKey(NodeId);
103+
end;
104+
105+
function ParseIntegerList(const S: string): TIntegerList;
106+
var
107+
Parts: TStringArray;
108+
Part: string;
109+
Value: integer;
110+
begin
111+
if S.Trim.IsEmpty then
112+
ShowUsage;
113+
114+
Parts := S.Split([',']);
115+
Result := TIntegerList.Create;
116+
try
117+
for Part in Parts do
118+
begin
119+
if not TryStrToInt(Trim(Part), Value) then
120+
begin
121+
Result.Free;
122+
ShowUsage;
123+
end;
124+
Result.Add(Value);
125+
end;
126+
127+
if Result.Count = 0 then
128+
begin
129+
Result.Free;
130+
ShowUsage;
131+
end;
132+
except
133+
on E: Exception do
134+
begin
135+
Result.Free;
136+
ShowUsage;
137+
end;
138+
end;
139+
end;
140+
141+
// Build tree from adjacency matrix and vertices
142+
function CreateTree(const AdjMatrix, Vertices: TIntegerList): TTree;
143+
var
144+
N, Row, Col, MatrixIndex: integer;
145+
Node: TNode;
146+
Vertex, AdjacentVertex: integer;
147+
begin
148+
N := Vertices.Count;
149+
if (N = 0) or (AdjMatrix.Count <> N * N) then
150+
ShowUsage;
151+
152+
// Create all nodes and add to tree
153+
Result := TTree.Create(Vertices.First);
154+
for Row in Vertices do
155+
Result.AddNode(TNode.Create(Row));
156+
157+
// Populate children based on adjacency matrix
158+
MatrixIndex := 0;
159+
for Row := 0 to N - 1 do
160+
begin
161+
Node := Result.GetNode(Vertices[Row]);
162+
for Col := 0 to N - 1 do
163+
begin
164+
if AdjMatrix[MatrixIndex] <> 0 then
165+
begin
166+
AdjacentVertex := Vertices[Col];
167+
if not Result.ContainsNode(AdjacentVertex) then
168+
begin
169+
Result.Free;
170+
ShowUsage;
171+
end;
172+
Node.AddChild(AdjacentVertex);
173+
end;
174+
Inc(MatrixIndex);
175+
end;
176+
end;
177+
end;
178+
179+
// Performs depth-first search for the target value.
180+
// This uses the iterative version with a TStack for performance.
181+
function DepthFirstSearch(Tree: TTree; Target: integer): boolean;
182+
var
183+
Stack: TIntegerStack;
184+
Visited: TIntegerSet;
185+
CurrentId: integer;
186+
CurrentNode: TNode;
187+
ChildId: integer;
188+
begin
189+
Result := False;
190+
if Tree = nil then Exit;
191+
192+
Stack := TIntegerStack.Create;
193+
Visited := TIntegerSet.Create;
194+
try
195+
Stack.Capacity := Tree.Nodes.Count;
196+
Visited.Capacity := Tree.Nodes.Count;
197+
198+
Stack.Push(Tree.RootId);
199+
200+
while Stack.Count > 0 do
201+
begin
202+
CurrentId := Stack.Pop;
203+
204+
if not Visited.Add(CurrentId) then
205+
Continue;
206+
207+
if CurrentId = Target then
208+
Exit(True);
209+
210+
CurrentNode := Tree.GetNode(CurrentId);
211+
if CurrentNode <> nil then
212+
for ChildId in CurrentNode.Children do
213+
Stack.Push(ChildId);
214+
end;
215+
finally
216+
Stack.Free;
217+
Visited.Free;
218+
end;
219+
end;
220+
221+
var
222+
AdjMatrix, Vertices: TIntegerList;
223+
Target: integer;
224+
Tree: TTree;
225+
begin
226+
if ParamCount <> 3 then
227+
ShowUsage;
228+
229+
AdjMatrix := ParseIntegerList(ParamStr(1));
230+
Vertices := ParseIntegerList(ParamStr(2));
231+
if not TryStrToInt(ParamStr(3), Target) then
232+
ShowUsage;
233+
234+
Tree := CreateTree(AdjMatrix, Vertices);
235+
try
236+
Writeln(BoolToStr(DepthFirstSearch(Tree, Target), 'true', 'false'));
237+
finally
238+
AdjMatrix.Free;
239+
Vertices.Free;
240+
Tree.Free;
241+
end;
242+
end.

0 commit comments

Comments
 (0)