Related
Good day,
Just to be clear: I am not looking for recursive or iterative solutions, Wikipedia has sufficient pseudocode to implement pre-, in- and post-order traversal of any tree.
I am interested in building a finite-state machine to traverse a binary tree.
A Tree consists of Nodes. Nodes have a LeftChild, a RightChild, and a Parent property.
The FSM halts at a Node at any given time, and can have as many states as required, but NO DYNAMIC STACK of any sort (which distinguishes it from a Turing machine). On input "GiveNext" the machine should halt on the next node (say traversing the tree pre-order.)
I've tried for quite a while now, and suspect, that it is not possible, but I am not sure. The problem is the need to keep track of recent decisions, so that on revisiting a Node via Parent one can turn right when left has been processed.
Thoughts?
Thanks in advance!
Herb
There may be a lot of constraints on this kind of exercises that I may be missing. I hope this is at least a bit usefull.
I am assuming that it is acceptable that the FSM is 'standing' at any given time on a 'current node' and therefore it has available inputs returning correct 0/1 values with info about this current node.
Inputs:
AmIALeftChild (equals 1 if the current node is hanging left of their parent node, otherwise 0)
AmIARightChild (1 if I am hanging left of my parent node, otherwise 0)
HaveLeftChild? (1 if I have a left child, otherwise 0 )
HaveRightChild? (1 if I have a right child, otherwise 0 )
And is it ok to 'traverse it' by following the instructions in these 3 outputs?
Outputs:
GoToLeftChild
GoToRightChild
GoUp
(only 1 of the 3 outputs can be true at any given time)
If both constraints are allowed, then you could build a FSM like this one:
States
Startup
NormalTraverse
GoBackFromLeft
GoBackFromRight
Finished
This is the State machine:
Start -> just go to NormalTraverse state (assuming we are on the root, right)
NormalTraverse ->
If HaveLeftChild=1 Then
Set GoToLeftChild=1 (and others outputs to 0)
Go to NormalTraverse
ElseIf HaveRightChild Then
Set GoToRightChild=1
Go to NormalTraverse
ElseIf AmIALeftChild Then
Set GoUp=1
Go to GoBackFromLeft
ElseIf AmIARightChild Then
Set GoUp=1
Go to GoBackFromRight
Else
Go to Finished.
GoBackFromLeft ->
If HaveRightChild Then
Set GoToRightChild=1
Go to NormalTraverse.
ElseIf AmIALeftChild Then
Set GoUp=1
Go to GoBackFromLeft
ElseIf AmIARightChild Then
Set GoUp=1
Go to GoBackFromRight
Else
Go to Finished.
GoBackFromRight
If AmIALeftChild Then
Set GoUp=1
Go to GoBackFromLeft
ElseIf AmIARightChild Then
Set GoUp=1
Go to GoBackFromRight
Else
Go to Finished.
Excuse my english now and please note that the code is not procedural, and the "IF's" should be mutually exclusive after correctly 'expanding' them 'bit-wisely'. but I am writing it these way to save a little of time. If you don't understand what I mean, please ask.
This is what I have come up with, after many sheets of paper worth half a tree, mainly to draw many binary trees (especially degenerated ones) to verify that the FSM works correctly.
The only variable required to be accessible all the time is the start node. This can be just any node in the tree: the FSM traverses just this subtree.
It is assumed, that the start node was already processed (or needs no processing). But it would be easy to integrate, if this is not the case for your application: Before the GO LEFT step, just add a test for the start node: I AM START. If TRUE, Report, otherwise continue as shown.
The individual actions mean:
GO LEFT - Make the current node's left child the current node, if there is any. The answer is OK if successful, or No Left if there is no such node.
GO RIGHT - Make the current node's right child the current node, if there is any. The answer is OK if successful, or No Right if there is no such node.
GO UP - Make the current node's parent the current node. There is just one resulting state. For the root, the parent does not exist, but the FSM will never attempt to access the root's parent.
I AM LEFT - Test if the current node is its parent left child. The answer is True or False.
I AM RIGHT - Test if the current node is its parent right child. The answer is True or False.
I AM START - Test if the current node is the start node. The answer is True or False.
I have been reading online websites and everybody says that using a priority queue will make it good, but I don't understand what is used as the "priority" here.
At the very beginning, is the first item on the priority queue always the starting point node? If so, when we extract the starting node with distance 0, how do we get its neighbors from the priority queue?
A priority queue Q stores a set of distinct elements. Each element
x has an associated key x.key
When Dijkstra is based on a priority queue. Then we store the vertices In the queue whose distances from the source are yet to be settled, keyed on their current distance from the source.
Take a look at this pdf where the algorithm is based on the abstract data structure called a priority queue, which can be implemented using a binary heap.
http://www.cs.bris.ac.uk/~montanar/teaching/dsa/dijkstra-handout.pdf
I was asked this question to reverse a singly linked list as big as having 7 million nodes by using threads efficiently. Using recursion doesn't look feasible if there are so many nodes so I opted for divide and conquer where in each thread be given a chunk of linked list which gets reversed by just making the node pointer point back to previous node by store a reference to current, future and past node and later adding it with reversed chunks from other threads. But the interviewer insisted that the size of the link list is not know, and you can do it without finding the size in an efficient manner. Well I couldn't figure it out , how would you go about it ?
Such questions I like to implement "top-down":
Assume that you already have a Class that implement Runnable or extends Thread out of which you can create instances and run, each instance receives two parameters: a pointer to a Node in the List and number of Nodes to reverse
Your main traverse all 7 million nodes and "marks" the starting points for your threads, say we have 7 threads, the marked points will be: 1, 1,000,000, 2,000,000,... save the marked nodes in an array or whichever data-structure you like
After you finished "marking the starting points, create the threads and give each one of them its starting point and the counter 1,000,000
After all the threads are done, "glue" each of the marking points to point back to the last node of the previous thread (which should be saved in another "static" ordered data-structure).
Now that we have a plan - all that's left to do is implement a (considerably easy) algorithm that, give the number N and a Node x, it will reverse the next N nodes (including x) in a singly linked list :)
I am looking for a concurrent algorithm which would help me in detecting cycles in a directed graph.
I know that the sequential algorithm uses a dfs with colouring, however I think that it will fail in a multi threaded environment. One example of a directed graph to illustrate it:
A->(B, C), B-> (D), D-> (E), C-> (E), E-> (F)
A
/ \
B C
| |
D |
\ /
E
|
F
(I hope the above makes it clear. The edges in the graph are all top to botton)
For the above directed graph, the following execution is possible during concurrent execution.
(the colouring scheme I assumed is white - unvisited, grey - execution of dfs not finished and black - finished execution and visit)
Dfs(B) by thread 1, which eventually colour E as grey and does a dfs(E) (leading to F). Before this is finished, thread 2 executes dfs(C). It realises that E is grey and reports a cycle which is obviously not the case.
I checked that Tarjan's algo could also be used for cycle detection, but again I do not think its execution will be correct in a multi threaded environment.
Could somebody please help me out on this?
Thanks.
As Ira states let each thread use its own colour.
But, If you have a fixed number of threads use a bit map for each of the colours.
As, long as you processor supports an atomic bit test and set (i.e. BTST on x86) you wont event need locking as each thread will be testing and setting a different bit.
If the bit is set then the item is coloured grey.
PS: If you need more colours then you can use more bits.
For multithreaded cycle detection, it's better to use a variant of the Kahn algorithm (for topological sort) instead of DFS. This uses the facts that:
1) If a directed graph is acyclic, then it has at least one vertex with no in-edges, and at least one vertex with no out-edges;
2) A vertex with no in-edges or no out-edges cannot participate in a cycle; so
3) If you remove a vertex with no in-edges or no out-edges, you're left with a smaller directed graph with the same cycles as the original.
So, to do a parallel cycle detection, you can:
1) First, use a parallel BFS to build a data structure that keeps track of the in-degree and out-degree of each vertex.
2) Then, in parallel, remove vertices with in-degree or out-degree 0. Note that removing a vertex will decrement the in-degrees or out-degrees of adjacent nodes.
3) When you're out of vertices to remove, you're left with all the vertices that are involved in cycles. If there aren't any, then the original graph was acyclic.
Both the parallel BFS (step 1) and parallel vertex removal (step 2) are easily accomplished with parallel work queues. In step 1, when you see a vertex for the first time, add a task to the queue that processes adjacent vertices. In step 2, when you decrement a vertex's in-degree or out-degree to 0, add a task to remove it from the graph.
Note that this algorithm works just as well if you remove only nodes with in-degree 0 or nodes with out-degree 0, but opportunities for parallelism are somewhat reduced.
You should easily find distributed deadlock detection algorithms, that adress the cycle detection problem.
I understand that distributed isn't exactly multithread, but you should still find hints there.
Edit : added a restricted solution.
This question is messy, i dont need a working solution, i need some psuedo code.
How would i solve this maze? This is a homework question. I have to get from point green to red. At every fork i need to 'spawn a thread' and go that direction. I need to figure out how to get to red but i am unsure how to avoid paths i already have taken (finishing with any path is ok, i am just not allowed to go in circles).
Heres an example of my problem, i start by moving down and i see a fork so one goes right and one goes down (or this thread can take it, it doesnt matter). Now lets ignore the rest of the forks and say the one going right hits the wall, goes down, hits the wall and goes left, then goes up. The other thread goes down, hits the wall then goes all the way right. The bottom path has been taken twice, by starting at different sides.
How do i mark this path has been taken? Do i need a lock? Is this the only way? Is there a lockless solution?
Implementation wise i was thinking i could have the maze something like this. I dont like the solution because there is a LOT of locking (assuming i lock before each read and write of the haveTraverse member). I dont need to use the MazeSegment class below, i just wrote it up as an example. I am allowed to construct the maze however i want. I was thinking maybe the solution requires no connecting paths and thats hassling me. Maybe i could split the map up instead of using the format below (which is easy to read and understand). But if i knew how to split it up i would know how to walk it thus the problem.
How do i walk this maze efficiently?
The only hint i receive was dont try to conserve memory by reusing it, make copies. However that was related to a problem with ordering a list and i dont think the hint was a hint for this.
class MazeSegment
{
enum Direction { up, down, left, right}
List<Pair<Direction, MazeSegment*>> ConnectingPaths;
int line_length;
bool haveTraverse;
}
MazeSegment root;
class MazeSegment
{
enum Direction { up, down, left, right}
List<Pair<Direction, MazeSegment*>> ConnectingPaths;
bool haveTraverse;
}
void WalkPath(MazeSegment segment)
{
if(segment.haveTraverse) return;
segment.haveTraverse = true;
foreach(var v in segment)
{
if(v.haveTraverse == false)
spawn_thread(v);
}
}
WalkPath(root);
Parallel Breadth-First Search
Search for parallel or multithread bread first traversal, which is basically what you're doing. Each time you come to a fork in your maze (where you can take one of several paths), you create a new worker thread to continue the search down each of the possible paths and report back which one gets you to the end.
It's similar to "simple" breadth first searches, except the subtrees can be searched in parallel.
If this were a pure tree data structure, you wouldn't need to lock, but since it's a graph traversal you will need to keep track of your visited nodes. So, the code which sets the "visited" flag of each node will need to be protected with a lock.
Here's a good example program. It uses audio feedback, so be sure your speakers are on.
http://www.break.com/games/maze15.html
Off hand, given your structure above, I could see solving this by adding an 'int Seen' to each MazeSegement instead of 'bool haveTraverse'. You could then use a interlocked increment on the 'Seen' variable as you're looping over the ConnectedPaths and only spawn a thread to take the path if the 'Seen' increment returns 1 (assuming Seen is initialized to 0).
So the code becomes something like
void WalkPath(MazeSegment segment)
{
foreach(var v in segment.ConnectedPaths)
{
if( Interlocked.Increment( &v.Path.Seen ) == 1)
spawn_thread(v.Path);
}
}
Other threads which might attempt to take the same path should get something >1. Because interlocked.increment would guarantee a thread-safe increment then we don't have to worry about 2 threads getting a result of '1' so only one thread should take a given path.
You can do this using the usual "read, calculate new value, compare-and-swap, repeat until CAS succeeds" method commonly found in lock-free programming.
All grid-squares in your maze start should hold a pointer representing the direction to move to reach the exit. Initially they all are "unknown".
Walk the maze starting at the exit. On each square reached, use compare and swap to replace "unknown" with the direction to the square this thread previously processed. If CAS fails, you've got a loop, prune that branch. If CAS succeeds, continue forward. When you assign a direction to the entrance, you now can follow the path to the exit.
Create a class (Worker) instances of which hold a path taken so far, and can only advance() through a straight corridor at given direction. At every intersection, drop the worker object which holds the path before intersection, and create two (or three) new objects, with a copy of that path and different turns taken.
Put these worker objects into a queue. Notice how every one of them is independent from another, so you may take several of them from the queue and advance() in parallel. You can simply create as many threads, or use a pool of threads according to the number of cores you have. Once any of the workers advance to the destination square, output the paths it holds, it is a solution.
Consider traversing the maze from exit to entry. In a real maze, blind alleys are intended to slow down motion form entry to exit, but rarely the other way around.
Consider adding a loop detection mechanism, e.g. by comparing intersections that make up your path with an intersection you encounter.
Consider using a hand-made linked list to represent the path. Note how inserting a new head to a linked list does not change the rest of it, so you can share the tail with other instances that don't modify it. This will reduce memory footprint and time needed to spawn a worker (only noticeable at rather large mazes).