Retaining the stack position of a recursive function between calls - java

This question is general, but I feel it is best explained with a specific example. Let's say I have a directory with many nested sub directories and in some of those sub directories there are text files ending with ".txt". A sample structure could be:
dir1
dir2
file1.txt
dir3
file2.txt
file3.txt
I'd be interested if there were a way in Java to build a method that could be called to return the successive text files:
TextCrawler crawler = new TextCrawler(new File("dir1"));
File textFile;
textFile = crawler.nextFile(); // value is file1.txt
textFile = crawler.nextFile(); // value is file2.txt
textFile = crawler.nextFile(); // value is file3.txt
Here is the challenge: No internal list of all the text files can be saved in the crawler object. That is trivial. In that case you'd simply build into the initialization a method that recursively builds the list of files.
Is there a general way of pausing a recursive method so that when it is called again it returns to the specific point in the stack where it left? Or will we have to write something that is specific to each situation and solutions necessarily have to vary for file crawlers, org chart searches, recursive prime finders, etc.?

If you want a solution that works on any recursive function, you can accept a Consumer object. It may look something like this:
public void recursiveMethod(Consumer<TreeNode> func, TreeNode node){
if(node.isLeafNode()){
func.accept(node);
} else{
//Perform recursive call
}
}
For a bunch of files, it might look like this:
public void recursiveMethod(Consumer<File> func, File curFile){
if(curFile.isFile()){
func.accept(curFile);
} else{
for(File f : curFile.listFiles()){
recursiveMethod(func, f);
}
}
}
You can then call it with:
File startingFile;
//Initialize f as pointing to a directory
recursiveMethod((File file)->{
//Do something with file
}, startingFile);
Adapt as necessary.

I think the state should be saved while you return from your recursive function, then you need to restore the state as you call that recursive function again. There is no generic way to save such a state, however a template can probably be created. Something like this:
class Crawler<T> {
LinkedList<T> innerState;
Callback<T> callback;
constructor Crawler(T base,Callback<T> callback) {
innerState=new LinkedList<T>();
innerState.push(base);
this.callback=callback; // I want functions passed here
}
T recursiveFunction() {
T base=innerState.pop();
T result=return recursiveInner(base);
if (!result) innerState.push(base); // full recursion complete
return result;
}
private T recursiveInner(T element) {
ArrayList<T> c=callback.getAllSubElements(element);
T d;
for each (T el in c) {
if (innerState.length()>0) {
d=innerState.pop();
c.skipTo(d);
el=d;
if (innerState.length()==0) el=c.getNext();
// we have already processed "d", if full inner state is restored
}
T result=null;
if (callback.testFunction(el)) result=el;
if ((!result) && (callback.recursiveFunction(el))) result=recursiveInner(el); // if we can recurse on this element, go for it
if (result) {
// returning true, go save state
innerState.push(el); // push current local state to "stack"
return result;
}
} // end foreach
return null;
}
}
interface Callback<T> {
bool testFunction(T element);
bool recursiveFunction(T element);
ArrayList<t> getAllSubElements(T element);
}
Here, skipTo() is a method that modifies the iterator on c to point to provided element. Callback<T> is a means to pass functions to class to be used as condition checkers. Say "Is T a folder" for recursive check, "Is T a *.txt" for return check, and "getAllSubclassElements" should also belong here. The for each loop is fron lack of knowledge on how to work with modifiable iterators in Java, please adapt to actual code.

The only way I can think of that would meet your exact requirement would be to perform the recursive tree walk in a separate thread, and have that thread deliver results back to the main thread one at a time. (For simplicity you could use a bounded queue for the delivery, but it is also possible to implement is using wait / notify, a lock object and a single shared reference variable.)
In Python, for example, this would be a good fit for coroutines. Unfortunately, Java doesn't have a direct equivalent.
I should add that using threads is likely to incur significant overhead in synchronization and thread context switching. Using a queue will reduce them to a degree provided that rate of "producing" and "consuming" is well matched.

Related

Balance a binary search tree

I'm trying to implement a binary search tree class in Java with a method that can rebalance the tree if there's a difference in height. I'm trying to do it by first storing the value of the nodes in an List (an attribute of the class).
I then want to take the middle element of this list and assign this to the root of the tree. After this I take the left- and right part of the list and do the same thing recursively to the left- and right children of the root and so on.
My algorithm doesn't seem to work though and I don't understand what I'm doing wrong. I wonder if someone can take a look at my code and explain what the problem is? What I do is basically pass the ordered list of elements of the tree (an attribute of the class) and the root into the function below:
public void build(BinaryNode<E> n,List<E> list) {
int idx = (int)Math.floor(list.size()/2);
if(n!=null) {
n.element = list.get(idx);
} else if(n==null) {
n = new BinaryNode<E>(list.get(idx));
}
if(!list.subList(0,idx).isEmpty()) {
build(n.left,list.subList(0,idx));
}
if(!list.subList(idx+1,list.size()).isEmpty() ){
build(n.right,list.subList(idx+1,list.size()));
}
return;
}
Kind regards,
Java method calls are "call by value". This means changing a parameter (like n in your case) has no effect outside of the method.
Try to define your method like this
public BinaryNode<E> build(List<E> list) { ... }
Try investigating about AVL tree
Some useful links:
https://en.wikipedia.org/wiki/AVL_tree
https://www.geeksforgeeks.org/avl-tree-set-1-insertion/

How to break from multiple instances calls of a recursive function?

I am creating a recursive function that will find the path between two nodes in a graph. The path will only be found if a node is not duplicated. If a node is connected to two other nodes two instances of the recursive function will be created. If there is a correct path from both of them the last found path will be set instead of the first one (line this.nodePath = clonedNodePath;). How can I break from all recursive calls when a path is found and not only break from the current recursive call instance? (I don't want to throw an exception)
private void process(String currentNodeId, List<String> currentNodePath) {
FlowNode currentFlowNode = modelInstance.getModelElementById(currentNodeId);
List<String> clonedNodePath = new ArrayList<>(currentNodePath);
if (currentFlowNode == null || clonedNodePath.contains(currentNodeId)) return;
clonedNodePath.add(currentNodeId);
if (currentNodeId.equals(finishNodeId)) {
this.nodePath = clonedNodePath;
return;
}
currentFlowNode.getOutgoing()
.stream()
.forEach(sequenceFlow -> process(sequenceFlow.getTarget().getId(), clonedNodePath));
}
The main problem lies in the iteration over the outgoing egdes.
You chose to do it with a Java8 stream, and this doesn't allow you to do an early abort (nitpicking: you can work around that "limitation", but that's clumsy).
Change that to a classical for loop, and your problem mostly disappears. Have your process() method return a boolean success indication, and inside the loop, if it gives true, return true out of this process() recursive call.
Or even more elegant: have the process() method return an Optional<List<String>>, either empty in case of failure, or filled with the path if successful. Then you also get rid of communicating via this.nodePath. And the process() method would better be named findPath().
P.S. I know it's en vogue to use streams, but there are situations where they're simply not the appropriate tool.

Listing all unimplemented methods called from within a method

We have a huge project where many methods have been declared upfront and implementations are in progress. All declared methods have a body which simply throws an exception, say, UnimplException.
Now since the methods have been declared and a valid (compilable) body has been provided, they can be called from within other methods.
Now the question is that is there any way to list all such unimplemented (having just a compilable body throwing a particular exception) methods given a particular method?
To illustrate more(the code is to convey the idea and not strictly compiler friendly):
class A {
methA () {
throw new UnimplException();
}
}
class B {
methB () {
// proper body
// and calls methA
A.methA();
// does something else
// and returns.
}
}
class C {
methC () {
// proper body
// calls methB
B.methB();
}
}
So, if we start from, say, methC, then we want to travel all the way down the method tree to reach to methA because methC calls methB (which is properly implemented and we are not interested) which in turn calls methA which is not properly implemented and that is what we want to find.
We want to search for all such unimplemented methods starting from a method and going few levels deep until we cover all such unimplemented methods.
We thought of JavaAssist but we aren't sure how to go down all the levels because it seems to be giving us all methods called from within a method but not recursively.
Any help is greatly appreciated :)
Have you seen this project: https://github.com/gousiosg/java-callgraph? This appears to do the Java introspection part, listing every method call from every method in a jar file. I'd try using that to do the heavy lifting of parsing your code, then just recurse through the results.
Something like:
Use the callgraph code to build a list of all method calls.
Save that data somewhere.
Recursively parse that structure to find matching methods.
So from your example, step 1 would give something like the following:
A:methA -> UnimplException:<init>
B:methB -> A:methA
C:methC -> B:methB
Then shove those in a Multimap and do a fairly straightforward recursive search:
// this is populated from the output of the callgraph code
com.google.common.collect.Multimap<String, String> methodMap;
void checkAllMethods() {
for (String method : methodMap.keySet()) {
List<String> callStack = new ArrayList<>();
if (doesMethodThrowUnimplException(method, callStack)) {
System.out.println(method);
// can print callStack too if interested
}
}
}
boolean doesMethodThrowUnimplException(String method, List<String> callStack) {
for (String child : methodMap.get(method)) {
// have to check the exact method name from callgraph
if (child.equals("UnimplException:<init>")) {
return true;
}
// recurse into child if not already seen
if (!callStack.contains(child)) {
callStack.add(child);
if (doesMethodThrowUnimplException(child, callStack)) {
return true;
}
callStack.remove(callStack.size() - 1);
}
}
return false;
}
Doesn't strictly satisfy your requirements as this will report any method which throws the UnimplException, not those who only throw the exception, but not sure if that matters.
Standard disclaimer - just typed this in - haven't compiled / run it, so may well be typos, but hopefully the idea helps.

Creating a filesystem implemented as a tree of singly linked lists in Java, using queues

We are given some Tree implemented as a tree of singly-linked lists. The insertPath function constructs a subtree (or uses an existing subtree) to store a new file, represented by filePathQueue into Tree<FileNode> t. The queue has an order IN -> [ “myFile” , “mySubDir” , “myDir” ] -> OUT, meaning I should be able to dequeue to get parent directories in order, and then check against the current level in the tree to see if the directory exists. Each FileNode has a value which is its name, and a boolean true to indicate that it is a file, and false to indicate it is a directory. I have pasted my code for insertPath as well as the findChild code. The rest was given to us and I assume professor-provided code is working. The only code I implemented was findChild and insertPath.
The exception gets thrown when the code creates a new FileSystem using the "sample" directory in my working folder, which contains three subdirectories, each with some files and their own subdirectories. To clarify: the constructor passes to me separate queues that represent each of the files and folders in the directory that I'm going to convert into a tree in a loop. So insertPath gets called multiple times with an updated tree being passed each time.
I have no idea why adding to the tree would throw an exception: it's telling me that I'm trying to dequeue an empty queue, but based on my code I should return out of it if the queue is empty? Exception is at the bottom. The lines with the problems are the recursive calls in the insertPath method as well as the dequeue at the top. Any help is greatly appreciated. Thanks.
public Tree<T> findChild(T otherLabel) {
if(getFirstChild() == null)
return null;
if(getFirstChild().getLabel() == otherLabel)
return getFirstChild();
Tree<T> test = getNextSibling();
while(test != null){
if(test.getLabel() == otherLabel)
return test;
test = test.getNextSibling();
}
return null;
}
public void insertPath(Tree<FileNode> t, QueueList<String> filePathQueue) {
try{
String check = filePathQueue.dequeue();
if(filePathQueue.size() == 0){
Tree<FileNode> file = new Tree<FileNode>(new FileNode(check,false));
t.addChild(file);
return;
}
Tree<FileNode> dir = new Tree<FileNode>(new FileNode(check,true));
Tree<FileNode> subdir = t.findChild(dir.getLabel());
if(subdir == null){
t.addChild(dir);
insertPath(t.getFirstChild(), filePathQueue);
}
insertPath(subdir, filePathQueue);
}
catch(Exception e){ e.printStackTrace(); return;}
InvalidOperationException: Queue empty: nothing to dequeue.
at QueueList.dequeue(QueueList.java:39)
at FileSystem.insertPath(FileSystem.java:38)
at FileSystem.insertPath(FileSystem.java:50)
at FileSystem.insertPath(FileSystem.java:48)
You're calling insertPath() recursively twice at the end of your insertPath() method:
public void insertPath(Tree<FileNode> t, QueueList<String> filePathQueue) {
...
if(subdir == null){
t.addChild(dir);
insertPath(t.getFirstChild(), filePathQueue); // ONCE
}
insertPath(subdir, filePathQueue); // TWICE
}
So, if going into the above block of code with a filePathQueue that only has one element, each of those calls to insertPath() is going to try to pull one out, and the second will throw the InvalidOperationException you demonstrated in your question.
It seems you either want to include an else block for when subdir is not null, or improve the first line of your insertPath() method to check for the filePathQueue size before you try to dequeue an item from it.
But seeing as this is homework - I'll let you decide which path to take. :-)

Efficient search in datastructure ArrayList

I've an ArrayList which contains my nodes. A node has a source, target and costs. Now I have to iterate over the whole ArrayList. That lasts for for over 1000 nodes a while. Therefore I tried to sort my List by source. But to find the corresponding pair in the List I tried the binary search. Unfortunately that works only if I want to compare either source or target. But I have to compare both to get the right pair. Is there another possibility to search an ArrayList efficient?
Unfortunately, no. ArrayLists are not made to be efficiently searched. They are used to store data and not search it. If you want to merely know if an item is contained, I would suggest you use HashSet as the lookup will have a time complexitiy of O(1) instead of O(n) for the ArrayList (assuming that you have implemented a functioning equals method for your objects).
If you want to do fast searches for objects, I recommend using an implementation of Dictionnary like HashMap. If you can afford the space requirement, you can have multiple maps, each with different keys to have a fast lookup of your object no matter what key you have to search for. Keep in mind that the lookup also requires implementing a correct equals method. Unfortunately, this requires that each key be unique which may not be a brilliant idea in your case.
However, you can use a HashMapto store, for each source, a List of nodes that have the keyed source as a source. You can do the same for cost and target. That way you can reduce the number of nodes you need to iterate over substantially. This should prove to be a good solution with a scarcely connected network.
private HashMap<Source, ArrayList<Node>> sourceMap = new HashMap<Source, ArrayList<Node>>();
private HashMap<Target, ArrayList<Node>> targetMap = new HashMap<Target, ArrayList<Node>>();
private HashMap<Cost, ArrayList<Node>> costMap = new HashMap<Cost, ArrayList<Node>>();
/** Look for a node with a given source */
for( Node node : sourceMap.get(keySource) )
{
/** Test the node for equality with a given node. Equals method below */
if(node.equals(nodeYouAreLookingFor) { return node; }
}
In order to be sure that your code will work, be sure to overwrite the equals method. I know I have said so already but this is a very common mistake.
#Override
public boolean equals(Object object)
{
if(object instanceof Node)
{
Node node = (Node) object;
if(source.equals(node.getSource() && target.equals(node.getTarget()))
{
return true;
}
} else {
return false;
}
}
If you don't, the test will simply compare references which may or may not be equal depending on how you handle your objects.
Edit: Just read what you base your equality upon. The equals method should be implemented in your node class. However, for it to work, you need to implement and override the equals method for the source and target too. That is, if they are objects. Be watchful though, if they are Nodes too, this may result in quite some tests spanning all of the network.
Update: Added code to reflect the purpose of the code in the comments.
ArrayList<Node> matchingNodes = sourceMap.get(desiredSourde).retainAll(targetMap.get(desiredTarget));
Now you have a list of all nodes that match the source and target criteria. Provided that you are willing to sacrifice a bit of memory, the lookup above will have a complexity of O(|sourceMap| * (|sourceMap|+|targetMap|)) [1]. While this is superior to just a linear lookup of all nodes, O(|allNodeList|), if your network is big enough, which with 1000 nodes I think it is, you could benefit much. If your network follows a naturally occurring network, then, as Albert-László Barabási has shown, it is likely scale-free. This means that splitting your network into lists of at least source and target will likely (I have no proof for this) result in a scale-free size distribution of these lists. Therefore, I believe the complexity of looking up source and target will be substantially reduced as |sourceMap| and |targetMap| should be substantially lower than |allNodeList|.
You'll need to combine the source and target into a single comparator, e.g.
compare(T o1, T o2) {
if(o1.source < o2.source) { return -1; }
else if(o1.source > o2.source) { return 1; }
// else o1.source == o2.source
else if(o1.target < o2.target) { return -1; }
else if(o1.target > o2.target) { return 1; }
else return 0;
}
You can use the .compareTo() method to compares your nodes.
You can create two ArrayLists. The first sorted by source, the second sorted by target.
Then you can search by source or target using binarySearch on the corresponding List.
You can make a helper class to store source-target pairs:
class SourceTarget {
public final Source source; // public fields are OK when they're final and immutable.
public final Target target; // you can use getters but I'm lazy
// (don't give this object setters. Map keys should ideally be immutable)
public SourceTarget( Source s, Target t ){
source = s;
target = t;
}
#Override
public boolean equals( Object other ){
// Implement in the obvious way (only equal when both source and target are equal
}
#Override
public int hashCode(){
// Implement consistently with equals
}
}
Then store your things in a HashMap<SourceTarget, List<Node>>, with each source-target pair mapped to the list of nodes that have exactly that source-target pair.
To retrieve just use
List<Node> results = map.get( new SourceTarget( node.source, node.target ) );
Alternatively to making a helper class, you can use the comparator in Zim-Zam's answer and a TreeMap<Node,List<Node>> with a representative Node object acting as the SourceTarget pair.

Categories