32

The recursion is sort of a 'divide and conquer' style, it splits up while getting smaller (Tree data structure), and I want it to break completely if a violation is found, meaning break all the recursive paths, and return true. Is this possible?

Bombe
  • 81,643
  • 20
  • 123
  • 127
Stasis
  • 585
  • 1
  • 4
  • 10
  • 1
    @Stasis: What do you mean by "all recursive paths". It seems like you are missing how recursion works. Notice if you have a tree structure that you are traversing recursively, you are not simultaneously exploring branches of the tree... you are exploring it 1 node at a time. So doing something like Tom's answer would work. If you somehow were using multiple threads to process different branches, you would need to keep some global state, but I don't think that's what you had in mind. We like to think of recursion as exploring many paths, but just understand that this is not happening at once. – Tom May 13 '09 at 05:13
  • For clarification, I wrote the comment above this, referring to a different Tom that posted an answer. – Tom May 13 '09 at 05:15
  • Yes, but what I was thinking of at first was, terminate this recursive "branch", for the lack of a better word, and instead of going to the other's to terminate, just pretend it didn't happen and send back false, rather than integers; or something of the sort. – Stasis May 13 '09 at 05:17
  • Stasis, the important question is: is each of your 'branches' a separate thread, or are you running a single-threaded recursive algorithm? – DJClayworth May 13 '09 at 15:25

11 Answers11

47

No matter what you do, you are going to have to unwind the stack. This leaves two options:

  1. Magic return value (as described by one of the Toms)
  2. Throw an exception (as mentioned by thaggie)

If the case where you want things to die is rare, this may be one of those situations where throwing an exception might be a viable choice. And before everyone jumps down my throat on this, remember that one of the most important rules of programming is knowing when it's appropriate to break the rule.

As it turns out, I spent today evaluating the zxing library from google code. They actually use exception throws for a lot of control structures. My first impression when I saw it was horror. They were literally calling methods tens of thousands of times with different parameters until the method doesn't throw an exception.

This certainly looked like a performance problem, so I made some adjustments to change things over to using a magic return value. And you know what? The code was 40% faster when running in a debugger. But when I switched to non-debugging, the code was less than 1% faster.

I'm still not crazy about the decision to use exceptions for flow control in this case (I mean, the exceptions get thrown all the time). But it's certainly not worth my time to re-implement it given the almost immeasurable performance difference.

If your condition that triggers death of the iteration is not a fundamental part of the algorithm, using an exception may make your code a lot cleaner. For me, the point where I'd make this decision is if the entire recursion needs to be unwound, then I'd use an exception. IF only part of the recursion needs to be unwound, use a magic return value.

Kevin Day
  • 16,067
  • 8
  • 44
  • 68
  • 2
    The OP writes "I want it to break completely if a violation is found", which sounds to me like an "exceptional condition", and is exactly what exceptions are for. – DJClayworth May 13 '09 at 15:27
  • 4
    (I'm the author of the zxing code) If a method's contract is "return the barcode found in this row", what would you like it to return when one doesn't exist? 'null' is a cop-out, since it is returning nothing. An exception is appropriate. But your point was performance. The other author challenged me on this initially. If you dig in the code you'll see we use a singleton exception to get around performance issues. – Sean Owen May 14 '09 at 17:12
  • 1
    I would always start from the position that the performance in an exceptional condition doesn't matter. If profiling showed me otherwise I would change my mind. – DJClayworth May 14 '09 at 19:30
  • Sean - very good to hear from you! I probably would have made the return result contain a marker for found/not-found (instead of returning null or throwing an exception). But like I said, performance is performance, right? – Kevin Day May 22 '09 at 17:41
  • DJ - agreed for the OP. In the case of zxing, the 'exceptional condition' isn't very exceptional (it's actually more of the norm than the exception). If I were designing it from scratch, I'd do it differently, but the performance measurements show that the current approach doesn't significantly impact speed. – Kevin Day May 22 '09 at 17:45
  • @SeanOwen just noticed your response - this probably isn't the best place to get into a design discussion, but one nice way of doing this is to have the methods return a BarCodeScanResult object that itself has a method foundBarcode() (and if that is true, then also a call to getResult() ). Totally agree that returning null is a bad idea. The advantage of a BarCodeScanResult is that it could contain other info (like a partial barcode that just happened to fail a checksum - that sort of thing). – Kevin Day Nov 21 '13 at 05:43
  • 1
    There is another notable reason to use exceptions and that is to be able to fail the scan directly from lots of deeply nested methods all over. Your method would require literally hundreds of custom classes to implement while an exception throws control straight to the top without thunking. It is actually faster in this context. – Sean Owen Nov 21 '13 at 10:29
22

You could return an error code, or modify some global variable so that each recursive instance knows to "kill itself".

Something of the sort.

int foo(bar){
     int to_the_next;

      if (go_recursive){
            to_the_next = foo(whisky_bar);

            if (to_the_next ==DIE) return DIE;
      }

      if (something_unexpected_happened) return DIE;

      process;//may include some other recursive calls, etc etc
}
Tom
  • 43,810
  • 29
  • 138
  • 169
  • 1
    Hmm thanks, I thought of something like that, but I just wanted to see if there was a way to just kill all recursive steps, but I'll just go with this. – Stasis May 13 '09 at 05:07
  • Well, technically it could be done. If you knew where your original function is located, you could jump to that stack frame, and pretend nothing happened. However, it requires assembly programming (cant think of any other way to do it) – Tom May 13 '09 at 05:11
  • Yeah I could possibly do it in x68, but this project has to be done in Java ><, and I wouldn't really know how to delve into stack frame's in Java. – Stasis May 13 '09 at 05:14
  • 1
    @Stasis: You always need to backtrack with recursion, it's how it works. Recursion works by use of the stack area of memory... you need to backtrack out of the function calls to resume execution of where you began recursing. This is the very nature/magic of recursion. It seems like you may need to understand recursion more. – Tom May 13 '09 at 05:18
  • 1
    @Tom: (the Tom 3 posts up... not me, 1 post up)... that is a gross optimization that is especially not even worthwhile of contemplating in Java. If you really can't afford the overhead, then do the "recursion" yourself in a loop with a stack. Also, if Java could do this, it would be through one of the memory management classes that is built-in, but that would probably add overhead using those classes. I would never recommend doing this in any high level programming language. Don't get in the habit of contemplating such premature optimizations that are not even good. Yuck :-P. – Tom May 13 '09 at 05:21
  • Hi (other) Tom that posted this answer... don't you think SO should implement a number system where an ID gets appended to a duplicate username in a post? So if I posted first, I'd be Tom. Then you post, and my name suddenly appears all over as Tom (1), and you appear as Tom (2)... something like that would make things less confusing... tell me if you think it's good and maybe I can make a feature request somehow. – Tom May 13 '09 at 05:27
  • Thanks to both Tom's. It seems that I'd forgotten the basis of recursion, and somehow got it in my head that it was simultaneous, hence my concern, and I wanted to limit the overhead, although I guess seeing as I'm not dealing with large red-black tree's (not necessarily, anyway) I won't need to go through so much precaution. Thanks again. – Stasis May 13 '09 at 05:31
  • the code is not breaking all recursive paths (as the original question stated) – Adeel Ansari May 13 '09 at 05:38
  • @Tom (the other): Yes, it is gross optimization. I was just saying that it could be done. I know its beyond java, and that java wise, its impossible. – Tom May 13 '09 at 13:12
  • @Tom (the other) Yes, some sort of control for duplicate username would be nice, but it would have to be clear. – Tom May 13 '09 at 13:19
  • Yes, this is the preferred way to go! Thanks. – David H. Mar 28 '14 at 18:19
7

I'd recommend an exception handling. That makes clear, that the recursion was aborted because of some violation (or other exception):

public void outer() {
  try {
    int i = recurse(0);
  } catch (OuchException ouch) {
    // handle the exception here
  }
}

private int recurse(int i) throws OuchException {

    // for tree-like structures
    if (thisIsALeaf) {
       return i;
    }

    // the violation test
    if (itHurts)
       throw new OuchException("That really hurts");

    // we also can encapsulate other exceptions
    try {
       someMethod();
    } catch (Exception oops) {
       throw new OuchException(oops);
    }

    // recurse
    return recurse(i++);
}

Sure, it violates the initial requirement to return 'true' upon abortion. But I prefer a clean separation of return values and notification on abnormal behaviour.

Andreas Dolk
  • 113,398
  • 19
  • 180
  • 268
5

If it's a single thread doing the recursion you could throw an exception. Bit ugly though - kind of using an exception as a goto.

boolean myPublicWrapperMethod(...) {
    try {
        return myPrivateRecursiveFunction(...);
    } catch (MySpecificException e) {
        return true;
    } 
} 

A better approach would be to eliminate the recursion and use a Stack collection holding a class representing what would have been recursive state, iterate in a loop and just return true when you want.

Tom
  • 43,583
  • 4
  • 41
  • 61
1

You can do something similar by storing a variable that tracks whether the recursions should break or not. You'd have to check it every recursion unfortunately but you can do it.

Joe Phillips
  • 49,743
  • 32
  • 103
  • 159
1

What you are asking is the definition of recursion.

At some point all recursive paths should break. Otherwise it will be an infinite recursion and stack overflow exception occurs.

So you should design the recursion function like that. An example binary search in a sorted array:

BinarySearch(A[0..N-1], value, low, high) {
       if (high < low)
           return -1 // not found
       mid = low + ((high - low) / 2)  // Note: not (low + high) / 2 !!
       if (A[mid] > value)
           return BinarySearch(A, value, low, mid-1)
       else if (A[mid] < value)
           return BinarySearch(A, value, mid+1, high)
       else
           return mid // found
}
Emre Köse
  • 653
  • 6
  • 14
0

I was able to move out of all recursive calls using a global variable.

boolean skipRecursivePaths = false;
private callAgain(){

if(callAgain){
  if(getOutCompletely){

    skipRecursivePaths = true;
    }
    if(skipRecursivePaths){
    return;
    }
}
Grambot
  • 4,370
  • 5
  • 28
  • 43
roho
  • 9
  • 1
0

The best way to get out of a recursive loop when an error is encountered is to throw a runtime exception.

throw new RuntimeException("Help!  Somebody debug me!  I'm crashing!");

Of course, this kills your program, but you should employ range checking and algorithm analysis to make sure your recursion does not throw such an exception. One reason you might want to break out of a recursive algorithm is that you are running low on memory. Here, it is possible to determine how much memory your algorithm will use on the stack. If you are coding Java, say, compare that calculation to

getMemoryInfo.availMem().

Let's say you are using recursion to find n!. Your function looks something like this:

public long fact(int n)
{
    long val = 1;
    for (int i  = 1, i<=n,i++)
        return val *= fact(i);
    return val;
}

Before you run it, check that you have (number of bytes in a long, 8 in Java) * n bytes in memory to hold the whole stack. Basically, with range and error checking in advance of the recursive method/function, you shouldn't need to break out. Depending on your algorithm, however, you may need to signal to the whole stack that you're good to go. If that's the case, Tom's answer works.

John R Perry
  • 3,916
  • 2
  • 38
  • 62
samdoj
  • 144
  • 8
0

Maybe you want to avoid recursion and replace it with a stack. This gives you the control to break out of the operation, while being able to do something that resembles a recursive operation. In fact you just emulate recursion by yourself.

I found a nice explanation here: http://haacked.com/archive/2007/03/04/Replacing_Recursion_With_a_Stack.aspx/

murphy
  • 524
  • 4
  • 16
0

Unless recursive calls are being evaluated in parallel, you probably just need to add some logic to check the first recursive call's value prior to making the second (and subsequent, if not a binary tree structure) recursive call.

public abstract class Tree {

    protected abstract boolean headIsViolation();

    protected abstract boolean isLeaf();

    public Tree getLeft();

    public Tree getRight();

    // Recursive
    public boolean checkViolation() {
        if(this.isLeaf()) {
            return this.headIsViolation();
        }

        // If needed, you could pass some sort of 'calculation state'
        // object through the recursive calls and evaluate the violation
        // through that object if the current node is insufficient
        if(this.headIsViolation()) {
            // Terminate the recursion
            return true;
        }

        // Fortunately, Java short-circuits ||
        // So if the left child is in violation, the right child will
        // not even be checked
        return this.getLeft().checkViolation() || this.getRight().checkViolation();
    }
}
Greg Case
  • 46,881
  • 3
  • 27
  • 21
-2

better to have a Boolean array

that way there is no global state

if(stop[0]) return;
Bacteria
  • 8,406
  • 10
  • 50
  • 67
itb
  • 7