views:

147

answers:

3

So I have this problem. I was trying to code a program to print all the valid possible arrangements of brackets i.e. for 3 brackets we can have ((())), (()()), ()()(), (())() etc.

I have a working code

public static void main(String[] args) {
    int number = 3; // No. of brackets
    int cn = number;
    int on = number;
    // open and closed brackets respectively
    char[] sol = new char[6];
    printSol(on, cn, sol, 0);
}

public static void printSol(int cn, int on, char[] sol, int k) {
    if (on == 0 && cn == 0) {
        System.out.println("");
        for (int i = 0; i < 6; i++) {
            System.out.print(sol[i]);
        }
    }

    else {
        if (on > 0) {
            if (cn > 0) {
                sol[k] = '(';
                printSol(on - 1, cn, sol, k + 1);
            }
        }

        if (cn > on) {
            sol[k] = ')';
            printSol(on, cn - 1, sol, k + 1);
        }
    }
}

Now the problem is that I want to do this using ArrayList instead of using char array. I tried but am getting errors. If anyone has any suggestions please let me know. The main purpose of asking this question is that I want to know when shall I prefer ArrayLists over arrays in Recursion problems.

P.S. I am sorry for the poor indentation as I had to type the whole program due to surfing restrictions and also thre might be some syntax errors but I tried my best. Thanks Mohit

+1  A: 

You want to avoid passing large data structures by-value while recursing as it can consume a lot of memory. That's about the only thing I can think of, in general. Passing a reference to an array or ArrayList is ok. I prefer ArrayList in general.

Look at Java's Stack class for this problem in particular.

Tony Ennis
Ok the error is that I am getting wrong solutions . It will take a lot of time to re-write the code using ArrayList. unlike the array the ArrayList keeps growing longer and longer . My recursive step is to call printSol(cn, on , sol) at each step where sol is ArrayList<Character> sol ;
peloooo
Tony I do not want to use any API's and want to get a low level knowledge. Can anybody help me in solving this problem using ArrayList ?
peloooo
I will paste the errorneous code and solution in some time for sure but this wrong solution is haunting me and could not stop myself to post it
peloooo
+1, stack is the right data structure. But I wouldn't use `Stack`, it's awful, is an admitted bigtime library design flaw, and should die a slow death. I'd use a `Deque` (concrete type `LinkedList`).
Mark Peters
You may need to remove the elements added in one alternative branch of the recursion before you enter the next branch. Or you can make a copy for use in the branch, to avoid modifying the original list.
starblue
Your question is more than just arrays vs arrayList it seems ;-)
Tony Ennis
*runs off to look at `Deque`*
Tony Ennis
@peloooo _Can anybody help me in solving this problem using ArrayList ?_ Peloooo, I'd no sooner use an ArrayList for this than drive a nail with a wrench. It is the wrong tool. Part of Java is understanding which collection to use.
Tony Ennis
Yeah Tony you are correct. I am trying to get a feel of which collections to use. I think this might help in better quality work in future
peloooo
@Mark Besides being synchronized, what is the worst thing about `Stack` ?
unhillbilly
@unhillbilly: 1) It's synchronized, as you said. 2) It uses inheritance instead of composition, meaning you can't treat it "just as a stack": it will always carry Vector's methods around as baggage, meaning people can do things to it that you shouldn't be able to do to a stack. Related, 3) "Stack" should've been the name of an interface so that you could at least have an interface solely for stack operations (similar to Queue and Deque) and had different implementations. 4) Though it's not officially deprecated, the Javadoc says not to use it and use `Deque` instead.
Mark Peters
@Mark Awesome! Thanks for spelling it out. I feel a bit smarter now!
unhillbilly
+2  A: 

I think you're doing just fine using char[]. It's quick and it's to the point.

I'd say most recursion problems you face in practice don't follow this pattern. That's because typically with problems demanding recursion you're performing a search on a search tree for one specific goal (one specific leaf node on a tree). You're performing iteration: you're trying to visit every leaf node on a tree, and perform an action for each.

With the common search algorithms (like a depth-first search), you thus wouldn't need to prepare the result as you recurse, but rather as you unwind, after you've found the goal.

But for cases where you do, char[] works great. You're basically simulating a stack through the parameters sol and k (sol holds the data while k points to the top of the stack). As others have noticed, you could use a stack directly (by passing a Deque<Character> implementation, commonly a LinkedList).

In my mind ArrayList is a step backwards. If you're going to use a collection, use one made for the problem.

Edit: Here's an untested implementation using a Deque instead:

public static void printSol(int cn, int on, Deque<Character> sol) {
    if (on == 0 && cn == 0) {
        System.out.println("");
        for ( Iterator<Character> it = sol.descendingIterator(); it.hasNext(); ) {
            System.out.println(it.next());
        }
    }

    else {
        if (on > 0) {
            if (cn > 0) {
                sol.push('(');
                printSol(on - 1, cn, sol);
                sol.pop();
            }
        }

        if (cn > on) {
            sol.push(')');
            printSol(on, cn - 1, sol);
            sol.pop();
        }
    }
}

//...
printSol(3, 3, new ArrayDeque<Character>(6));

As you can see, very few changes.

Edit 2: One thing we haven't discussed at all for this specific problem is StringBuilder.

StringBuilder is a mutable String type that allows you to easily append and remove characters. This would be a great solution for this problem as well:

public static void printSol(int cn, int on, StringBuilder sol) {
    if (on == 0 && cn == 0) {
        System.out.println(sol);
    }

    else {
        if (on > 0) {
            if (cn > 0) {
                sol.append('(');
                printSol(on - 1, cn, sol);
                sol.deleteCharAt(sol.length()-1);
            }
        }

        if (cn > on) {
            sol.append(')');
            printSol(on, cn - 1, sol);
            sol.deleteCharAt(sol.length()-1);
        }
    }
}
Mark Peters
Thanks for the reply. In context to your reply let's take a problem where I need to find all the possible paths in a tree(from root to leaves). This is a similar recursive problem to one I posted where I would like to use an array and use it as a stack. I have no problems in accepting char[] as the solution but the problem is that am unable to understand when to use ArrayList in recursion. I am new to java.
peloooo
@peloooo: I would say there is very, very little use for an ArrayList in recursion. Ever. Definitely not in this example. Most times where you're "building the path" to the leaf node, you want a stack. There are two main implementations of a stack: a linked list where you hold only the head node, or an array where you maintain a pointer to the top of the stack. If you want to implement it without a class, you're doing fine. But if you want to use a collection class, those two implementations are represented by `LinkedList` and `ArrayDeque` respectively.
Mark Peters
The advantage of using the array as you have is that with a Stack, you have to go to an intermediate data structure to build the result (e.g., to print them in order, you have to pop them onto another stack first to reverse the order). But the beauty of Deque is that you can switch to using it as a queue at the end, and use `Deque.iterator()` to get them in FIFO order.
Mark Peters
Mark, I am new to java and am particularly stubborn ( My weakness) in using API's . Can you please elaborate a little with a piece of code ?
peloooo
@peloooo: way ahead of ya.
Mark Peters
Hey thanks Mark for the solution but the FIFO output will just give reverse solution ;-) for our case. Rest is fine.
peloooo
@peloooo: It shouldn't; give it a try. The FIFO output will be the exact same as iterating through the array in forward order as you are doing. Printing it in LIFO order would print the most recently added bracket first, which is the opposite of your `char[]` implementation. You can use `Deque.descendingIterator()` to iterate in LIFO ordering, but I'm sure that's not what you want.
Mark Peters
Ok thats a small issue but I got reverse result on testing with the code above.
peloooo
So sorry @peloooo, I misread the Javadoc! Updating answer now.
Mark Peters
@peloooo APIs can save you a lot of time. Definitely need to get over that weakness.
AHungerArtist
A: 

I realized nobody (including myself) actually answered your question. I think you've been convinced using an ArrayList isn't desirable here. But how could you make it work?

The easiest way is to basically fake a stack with it:

public static void printSol(int cn, int on, ArrayList<Character> sol) {
   //...
   sol.add('(');
   printSol(on - 1, cn, sol);
   sol.remove(sol.size() - 1);
Mark Peters