mirror of
https://github.com/mfocko/blog.git
synced 2024-11-22 13:03:47 +01:00
ib002(graphs): convert pseudocode to Ada
cause why not… Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
parent
a4a9bcfcd2
commit
2c0d77b689
1 changed files with 119 additions and 75 deletions
|
@ -21,81 +21,108 @@ On the other hand, we have seen iterative implementation in the exercises and I
|
||||||
|
|
||||||
### Recursive DFS implementation from exercises without colors
|
### Recursive DFS implementation from exercises without colors
|
||||||
|
|
||||||
```
|
```ada showLineNumbers
|
||||||
FUNCTION VisitedDFS(u, Visited) IS
|
function VisitedDFS(u: Vertex, visited: VertexSet) return VertexSet is
|
||||||
Visited <- Union(Visited, { u })
|
v: Vertex;
|
||||||
FOR v IN u.successors DO
|
begin
|
||||||
IF v NOT IN Visited THEN
|
visited.Union(To_Set(u));
|
||||||
Visited <- VisitedDFS(v, Visited)
|
|
||||||
FI
|
|
||||||
OD
|
|
||||||
|
|
||||||
RETURN Visited
|
for v in u.successors loop
|
||||||
END
|
if not Contains(visited, v) then
|
||||||
|
visited := visitedDFS(v, Visited);
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
return visited;
|
||||||
|
end VisitedDFS;
|
||||||
```
|
```
|
||||||
|
|
||||||
This implementation is correct, does the DFS traversal as it should, however it has one „smallish“ downside and that is the time complexity. The usage of set raises the time complexity, of course it is implementation dependant. However in case of either RB-tree or hash-table implementation, we get look-up in time $\mathcal{O}(n)$ for hash-table in worst-case or $\mathcal{O}(\log n)$ for the other in the worst-case. Both are not ideal compared to checking color on vertex.
|
This implementation is correct, does the DFS traversal as it should, however it has one „smallish“ downside and that is the time complexity. The usage of set raises the time complexity, of course it is implementation dependant. However in case of either RB-tree or hash-table implementation, we get look-up in time $\mathcal{O}(n)$ for hash-table in worst-case or $\mathcal{O}(\log n)$ for the other in the worst-case. Both are not ideal compared to checking color on vertex.
|
||||||
|
|
||||||
### Iterative DFS from the exercises
|
### Iterative DFS from the exercises
|
||||||
|
|
||||||
```
|
```ada showLineNumbers
|
||||||
PROCEDURE IterDFS(u)
|
procedure IterDFS(u: Vertex) is
|
||||||
stack <- empty stack
|
stack: StateVector;
|
||||||
Push(stack, (u, 0))
|
i, time: Integer;
|
||||||
u.color <- gray
|
v: Vertex;
|
||||||
time <- 1
|
begin
|
||||||
u.d <- time
|
stack.Append(VertexState(u, 0));
|
||||||
|
u.color := Gray;
|
||||||
|
time := 1;
|
||||||
|
u.d := time;
|
||||||
|
|
||||||
WHILE NOT Empty(stack) DO
|
while not stack.Is_Empty loop
|
||||||
(u, k) <- Pop(stack)
|
u := stack.Last_Element.Vertex;
|
||||||
|
i := stack.Last_Element.NextIndex;
|
||||||
|
stack.Delete_Last;
|
||||||
|
|
||||||
IF k < Length(u.successors) THEN
|
if i < u.successors.Length then
|
||||||
// search is not finished, is pushed back to stack
|
-- search is not finished, is pushed back to stack
|
||||||
Push(stack, (u, k + 1))
|
stack.Append(VertexState(u, k + 1));
|
||||||
|
|
||||||
v <- u.successors[k + 1]
|
v := u.successors.Element(i);
|
||||||
IF v.color = white THEN
|
if v.color = White then
|
||||||
Push(stack, (v, 0))
|
stack.Append(VertexState(v, 0));
|
||||||
v.color <- gray
|
v.color := Gray;
|
||||||
time <- time + 1
|
time := time + 1;
|
||||||
v.d <- time
|
v.d := time;
|
||||||
FI
|
end if;
|
||||||
ELSE
|
else
|
||||||
// u has no other successors, we can finish the search
|
-- u has no other successors, we can finish the search
|
||||||
time <- time + 1
|
time := time + 1;
|
||||||
u.f <- time
|
u.f := time;
|
||||||
u.color <- black
|
u.color := Black;
|
||||||
FI
|
end if;
|
||||||
OD
|
end loop;
|
||||||
END
|
|
||||||
|
end IterDFS;
|
||||||
```
|
```
|
||||||
|
|
||||||
As we can see, there is some ordering in which we search through the successors. Time complexity is OK, stack holds at most all vertices (they must be on the current path).
|
As we can see, there is some ordering in which we search through the successors. Time complexity is OK, stack holds at most all vertices (they must be on the current path).
|
||||||
|
|
||||||
### My iterative with path in stack
|
### My iterative with path in stack
|
||||||
|
|
||||||
```
|
```ada showLineNumbers
|
||||||
PROCEDURE DFS(G, start) IS
|
procedure DFS(start: Vertex) is
|
||||||
path <- [ start ]
|
path: VertexVector;
|
||||||
time <- 1
|
time: Integer;
|
||||||
start.d, start.color <- time, gray
|
hasSuccessor: Bool;
|
||||||
|
successor: Vertex;
|
||||||
|
begin
|
||||||
|
path.Append(start);
|
||||||
|
time := 1;
|
||||||
|
|
||||||
WHILE NOT Empty(path) DO
|
start.d := time;
|
||||||
hasSuccessor <- false
|
start.color := Gray;
|
||||||
FOR successor IN path[-1].successors DO
|
|
||||||
IF successor.color = white THEN
|
while not path.Is_Empty loop
|
||||||
hasSuccessor <- true
|
hasSuccessor := false;
|
||||||
successor.d, successor.color <- ++time, gray
|
|
||||||
path <- Append(path, successor)
|
for successor in path.Last_Element.successors loop
|
||||||
BREAK
|
if successor.color = White then
|
||||||
FI
|
hasSuccessor := true;
|
||||||
OD
|
|
||||||
IF NOT hasSuccessor THEN
|
successor.d := time + 1;
|
||||||
lastVertex <- Pop(path)
|
successor.color := Gray;
|
||||||
lastVertex.f, lastVertex.color <- ++time, black
|
time := time + 1;
|
||||||
FI
|
|
||||||
OD
|
path.Append(successor);
|
||||||
END
|
|
||||||
|
exit;
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
if not hasSuccessor then
|
||||||
|
path.Last_Element.f := time + 1;
|
||||||
|
path.Last_Element.color := Black;
|
||||||
|
|
||||||
|
time := time + 1;
|
||||||
|
path.Delete_Last;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
end loop;
|
||||||
|
end DFS;
|
||||||
```
|
```
|
||||||
|
|
||||||
This approach is similar to the iterative solution from the exercises, but it does not keep the index of the next successor, therefore it always iterates through all of them, which raises the time complexity.
|
This approach is similar to the iterative solution from the exercises, but it does not keep the index of the next successor, therefore it always iterates through all of them, which raises the time complexity.
|
||||||
|
@ -104,27 +131,44 @@ This approach is similar to the iterative solution from the exercises, but it do
|
||||||
|
|
||||||
On the other hand, we do not actually have to depend on the representation of the graph. In this case, we just _somehow_ obtain the iterator (which yields all of the succesors) and keep it in the stack.
|
On the other hand, we do not actually have to depend on the representation of the graph. In this case, we just _somehow_ obtain the iterator (which yields all of the succesors) and keep it in the stack.
|
||||||
|
|
||||||
```
|
```ada showLineNumbers
|
||||||
PROCEDURE DFS(G, start) IS
|
procedure DFS(start: Vertex) is
|
||||||
path <- [ (start, Iterator(start.successors)) ]
|
path: StateVector;
|
||||||
time <- 1
|
time: Integer;
|
||||||
start.d, start.color <- time, gray
|
current: State;
|
||||||
|
nextVertex: Vertex;
|
||||||
|
begin
|
||||||
|
path.Append(State(start));
|
||||||
|
time := 1;
|
||||||
|
|
||||||
WHILE NOT Empty(path) DO
|
start.d := time;
|
||||||
lastVertex, successors <- path[-1]
|
start.color := Gray;
|
||||||
|
|
||||||
IF NOT MoveNext(successors) THEN
|
while not path.Is_Empty loop
|
||||||
Pop(path)
|
current := path.Last_Element;
|
||||||
lastVertex.f, lastVertex.color <- ++time, black
|
|
||||||
ELSE IF successors.Current.color = white THEN
|
if not Move_Next(current.successors) then
|
||||||
nextVertex <- successors.Current
|
path.Delete_Last;
|
||||||
nextVertex.d, nextVertex.color <- ++time, gray
|
|
||||||
path <- Append(path, (nextVertex, Iterator(nextVertex.successors)))
|
time := time + 1;
|
||||||
FI
|
current.vertex.f := time;
|
||||||
OD
|
|
||||||
END
|
current.vertex.color := Black;
|
||||||
|
else if current.successors.Value.color = white then
|
||||||
|
nextVertex := current.successors.Value;
|
||||||
|
|
||||||
|
time := time + 1;
|
||||||
|
nextVertex.d := time;
|
||||||
|
|
||||||
|
nextVertex.color := Gray;
|
||||||
|
|
||||||
|
path.Append(State(nextVertex));
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
end DFS;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
( The way we manipulate with the iterators is closest to the C# implementation. Apart from the `Iterator` thing :) In case you tried to implement it in C++, you would more than likely need to change the check, since you would get first successor right at the beginning )
|
( The way we manipulate with the iterators is closest to the C# implementation. Apart from the `Iterator` thing :) In case you tried to implement it in C++, you would more than likely need to change the check, since you would get first successor right at the beginning )
|
||||||
|
|
||||||
So here we don't keep indices, but the iterators. We can also check existence of other successors easily: by the iterator moving after the last successor.
|
So here we don't keep indices, but the iterators. We can also check existence of other successors easily: by the iterator moving after the last successor.
|
||||||
|
|
Loading…
Reference in a new issue