4

I'm trying to find all permutations of a string and sort them alphabetically.

This is what I have so far:

public class permutations {

        public static void main(String args[]) {
            Scanner s = new Scanner(System.in);
            System.out.print("Enter String: ");
            String chars = s.next();
            findPerms("", chars);
        }

        public static void findPerms(String mystr, String chars) {

            List<String> permsList = new ArrayList<String>();

                if (chars.length() <= 1)
                        permsList.add(mystr + chars);
                        //System.out.print(mystr + chars + " ");

                else
                        for (int i = 0; i < chars.length(); i++) {
                            String newString = chars.substring(0, i) + chars.substring(i + 1);
                            findPerms(mystr + chars.charAt(i), newString);
                        }

               Collections.sort(permsList);

               for(int i=0; i<permsList.size(); i++) {
                    System.out.print(permsList.get(i) + " ");
               }
       }
}

IF I enter a string "toys" I get:

toys tosy tyos tyso tsoy tsyo otys otsy oyts oyst osty osyt ytos ytso yots yost ysto ysot stoy styo soty soyt syto syot

What am I doing wrong. How can I get them in alphabetical order? Thanks!

relyt
  • 679
  • 6
  • 14
  • 26

5 Answers5

8

You're calling your sort routine from within the recursive method that finds all permutations of your String, before it's been fully populated

import java.util.*;

public class permutations {

        public static void main(String args[]) {
            Scanner s = new Scanner(System.in);
            System.out.print("Enter String: ");
            String chars = s.next();
            List<String> myList = new ArrayList<String>();
            findPerms(myList, "", chars);

            Collections.sort(myList);

            for(int i=0; i<myList.size(); i++) {
               System.out.print(myList.get(i) + " ");
            }

        }

        public static void findPerms(List<String> permsList, String mystr, String chars) {

            if (chars.length() <= 1)
                permsList.add(mystr + chars);    
            else
            for (int i = 0; i < chars.length(); i++) {
                String newString = chars.substring(0, i) + chars.substring(i + 1);
                findPerms(permsList, mystr + chars.charAt(i), newString);
            }

       }
}
Amir Afghani
  • 37,814
  • 16
  • 84
  • 124
  • 2
    The list should also be passed in (recursively), rather than constantly reinitialized. And the prints should be moved out of findperms. – Matthew Flaschen Mar 23 '10 at 01:11
  • Agreed - I'm going to post something in a second – Amir Afghani Mar 23 '10 at 01:14
  • BTW, the code you posted won't compile as is. You should fix that. I would if I could but I don't have 2000 rep yet ;) – Amir Afghani Mar 23 '10 at 01:19
  • Amir. It actually does compile and outputs what I posted above. I'm still trying to get it right based on what Matthew pointed out...but any other info would be appreciated. – relyt Mar 23 '10 at 01:23
  • When I copied your code and pasted it in a file I got compiler errors from not importing Scanner, etc. I posted the working solution with an explanation. – Amir Afghani Mar 23 '10 at 01:24
  • Amir that's odd. Seemed to work for me. Anyway, I looked over your solution and I understand what you did and it does make sense now. Basically permsList was being reset everytime findPerms was called, right? – relyt Mar 23 '10 at 01:26
  • I don't like how this algorithm deals with repeat strings, like: "aaaa". – Amir Afghani Mar 23 '10 at 01:28
  • Not just that, you were calling sort in your recursive function. – Amir Afghani Mar 23 '10 at 01:29
  • Ok got it. Thanks again. This certainly works and will help me in the future. – relyt Mar 23 '10 at 01:30
2

Some of the comments already point out that your recursive routine can't do a sort at the leaf nodes and expect to sort the whole list. You'd have to return the accumulated strings in a collection and then sort and print them once at the end.

More importantly, there is a nice algorithm for permuting an array in lexical order. It's used by the next_permutation library function in C++ (which you can look up for explanations), but it's easy enough to translate to java. You extract a char[] array, maybe with getCharArray, sort it with Arrays.sort and run this until it returns false.

/** Helper function */
void reverse(char[] a, int f, int l)
  {
  while(l>f)
    {
    char tmp = a[l];
    a[l] = a[f];
    a[f] = tmp;
    l--; f++;
    }
  }

/** actual permutation function */
boolean next_permutation(char[] a)
  {
  if(a.length < 2) return false;
  for(int i = a.length-1; i-->0;)
    if(a[i] < a[i+1]) 
    { 
    int j=a.length-1;
    while(!(a[i] < a[j]))
      j--;
    char tmp=a[i];
    a[i]=a[j];
    a[j]=tmp;
    reverse(a, i+1, a.length-1); 
    return true; 
    }
  reverse(a, 0, a.length-1); 
  return false; 
  }

Once you understand what it does, just run while(next_permutation(array)) {println(array);} and you're doing fine. Note that this is very bad for arrays over 13 or so elements.

Brian
  • 8,454
  • 5
  • 27
  • 30
0

You need to sort the results of the call of findperms, not inside the recusive call.

DVK
  • 126,886
  • 32
  • 213
  • 327
  • DVK I think I know what you mean, but can you expand a little more? – relyt Mar 23 '10 at 01:10
  • @relyt - I assume Amir's answer provides enough of an explanation, if not please reply and i'll elaborate – DVK Mar 23 '10 at 01:22
0

You could put all the permutations that you have already gotten and put them in a TreeSet or PriorityQueue which will put them in order. You would then have to put them back into your ArrayList.

Or you could use a Collections Sort which sorts your ArrayList.

I recommend the last option. Here is an example if you do not understand it.

twodayslate
  • 2,803
  • 3
  • 27
  • 43