简体   繁体   中英

Subset Generator gives out java heap space error

Here are the errors I receive when running the tester class. I keep looking at where the code is pointing but I don't see where the issue is. It keeps saying I am also out of Java heap space, not sure what that is. I also am not sure if my recursive getsubset() method is even working correctly, as I can't even compile my tester class. If there are any other mistakes in my code be free to point them out. Thank you!

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at java.util.Arrays.copyOfRange(Arrays.java:3209)
        at java.lang.String.<init>(String.java:215)
        at java.lang.StringBuilder.toString(StringBuilder.java:430)
        at SubsetGenerator.getSubsets(SubsetGenerator.java:68)
        at SubsetGenerator.getSubsets(SubsetGenerator.java:64)
        at SubsetGeneratorTester2.main(SubsetGeneratorTester2.java:23)
Press any key to continue...





 import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
   Prints subsets of String
*/

public class SubsetGenerator
{
    private String word="";

    private ArrayList<String> subsets;

    /**
        Constructs a word to generate subsets from
        @param text input by user
    */
    public SubsetGenerator(String textinput)
    {
        word=textinput;
        subsets = new ArrayList<String>();
    }



    /**
        retrieves word
        @return the word
    */
    public String getWord()
    {
        return word;
    }




    /**
        get subsets
        @return subset arraylist
    */
    public ArrayList<String> getSubsets()
    {
        if(word.length() == 1)
        {
            subsets.add(word);
            return subsets;
        }
        else
        {

            String removed = word.substring(0,1);
            word = word.substring(1);

            getSubsets();

            for (int i = 0; i < subsets.size(); i++)
            {
                String temp = removed + subsets.get(i);
                subsets.add(temp);
            }
            subsets.add(removed);
            return subsets;
        }
    }

    //sort subsets
    public void sortSubsets()
    {
        Collections.sort(subsets);
    }
}



import java.util.Collections;
import java.util.ArrayList;
import java.util.List;

/**
   This program tests the subset generator.
*/
public class SubsetGeneratorTester2
{
   public static void main(String[] args)
   {
      SubsetGenerator generator = new SubsetGenerator("rum");

      List<String> subsets = generator.getSubsets();
      // Sort the result for checking
      Collections.sort(subsets);
      System.out.println(subsets);
      System.out.println("Expected: [, m, r, rm, ru, rum, u, um]");
   }
}

The problem appears to be with the loop. If its not empty, an element is added so the size increases. Then since an element was empty, i+1 cannot ever be greater than or equal to the new size. This will very easily exhaust the heap. This fails however on the empty string with a runtime error immediately.

I can confirm that the loop is the culprit. Fixed this by simply moving the index out of the loop. That way it won't update as elements are added.

        int size = subsets.size();
        for (int i = 0; i < size; i++)
        {
            String temp = removed + subsets.get(i);
            subsets.add(temp);
        }

However, there was another issue.

Your method resulted in the set:

[m, r, rm, ru, rum, u, um]

This was easily changeable, since your base case was wrong. I also didn't want to modify too much of the code (but there is a better way to do this!)

In your example, the empty string would never work, however logically it should. The way I would handle this, is as follows (in pseudo code):

List subset(String str):
    if(length == 0):
        return [""];
    x = subset(str.substring(1));
    result = [];
    for s in x:
        result += [s, str.charAt(0) + s];
    return result;

This of course is pseudo code (and close to python actually). I didn't want to give it all away, but the basic merit is to understand how these can be accomplished.

The important thing to note is that for each element, we add 2 strings to the list. One with the first character of the current string and one without the first character of the current string.

Consider some basic cases:

subset("")   -> [""]
subset("a")  -> ["", "a"] 
subset("ab") -> ["", "a", "b", "ab"]

Hopefully you can see the pattern. For each string we add one with the character and one without.

I will give you another solution which is more clear than yours. First cut off a character from word. Then use that character to connect the remainder. Finally call getSubsets() recursively. If the word.length is zero, it reached the bottom and it will return.

   public ArrayList<String> getSubsets(){
         if(word.length()==0){
             subsets.add("");
             return subsets;
         }
         else{
             String removed=word.substring(0,1);
             word=word.substring(1);
             subsets.add(removed);

             for(int i=0;i<word.length();i++){
                String temp=removed+word.substring(0,i+1);
                subsets.add(temp);
             }
         }

         getSubsets();
         return subsets;
   }

It's my anwser:

root@MQ-PC:/home/java/algorithm# java SubsetGenerator 
[r, ru, rum, u, um, m, ]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM