2013-11-28 1 views
0

Я пытаюсь написать программу на Java, которая распаковывает сжатый оператор RLE с использованием рекурсии, но я постоянно получаю ошибки переполнения стека, и я не знаю почему.Рекурсивный метод декомпрессии Java RLE [ошибка stackoverflow]

Вот что я написал до сих пор:

public class StringRec 
{ 
    public static void main (String args[]){ 

     System.out.println(decompress("wed4d")); 
    } 
    //Version 0.1 
    public static String decompress(String compressedText) 
    { String cText = compressedText; 
     StringBuffer newString = new StringBuffer(); 

     int i = 0; 

     if (cText==""){return newString.toString();} 

     if(!cText.isEmpty()){ 

      if(Character.isLetter(cText.charAt(i))){ 
       newString.append(cText.charAt(i)); 

       cText = cText.substring(1,cText.length()); 

       return decompress(cText); 
       //remove first letter, return new modified string with removed first letter to decompress. 
      } 
      if(Character.isDigit(cText.charAt(i))){ 
       int c = cText.charAt(i)-'0'; 

       if (c==0){ 
        cText = cText.substring(2,cText.length());} 

        return decompress(cText); 
        //delete c and the letter after it and send new modified string to decompress. 
        } 

       }else { 
        newString.append(cText.charAt(i+1)); 
        int c = cText.charAt(i); 
        c--; 
        String num = ""+c; 
        cText = cText.replaceFirst(num, Character.toString(cText.charAt(i))); 

        return decompress(cText); 
        //appends character after number to newString, decrements the number and returns 
        //the new modified string to decompress with the first number decremented by one 
        } 
     return newString.toString(); 

    } 
} 

Мой базовый вариант для рекурсии является пустой строкой, если строка начинается с буквы, что письмо добавляется к StringBuffer NewString только один раз, и что первый буква исходной строки удаляется из последовательности строк, а новая строка передается для распаковки; если он начинается с числа, которое равно нулю, первые два символа строки удаляются, а новая строка передается для распаковки.

Если это число больше 0 [else], то буква перед ним добавляется в stringbuffer newString и число уменьшается и заменяет номер в начале строки и передает новую строку [с помощью первоначальный первый номер символа - 1] для распаковки.

+0

Как долго длится строка? Java не поддерживает неограниченную рекурсию; рекурсивные алгоритмы работают только в том случае, если они не слишком усложняются. – user2357112

+0

Не знаю о переполнении стека, но каждый раз, когда вы вызываете 'распаковывать' рекурсивно, рекурсивная подпрограмма создаст ** новую **' новую строку '. Новый вызов подпрограммы ** не будет ** добавляться к той же «новой строке», что использовался старым вызовом. Вероятно, вашему рекурсивному методу нужно взять 'newString' в качестве параметра, который он продолжает передавать самому себе, а затем внешняя нерекурсивная подпрограмма должна будет инициализировать его перед вызовом рекурсивной подпрограммы в первый раз. – ajb

+0

Вы пробовали переходить через свой код в отладчик?Это и несколько хорошо размещенных вызовов журнала «System.out.println» помогут вам узнать, почему ваша рекурсия не достигает базового случая и вызывает ошибку ... – Krease

ответ

1

Я считаю, что бесконечная рекурсия происходит из-за этого:

int c = cText.charAt(i); 
c--; 
String num = ""+c; 
cText = cText.replaceFirst(num, Character.toString(cText.charAt(i))); 

Если персонаж 1, то c будет 65, значение ASCII символа '1'. Тогда num будет установлен на строку "64", и если в вашей строке нет "64", метод будет продолжать называть себя одной и той же строкой снова и снова. Объявление c как char должно исправить это. Кроме того, обратите внимание, что replaceFirst говорит, чтобы искать шаблон, соответствующий первому аргументу, и заменить его на второй. У вас может быть это назад. Кроме того, см. Мой комментарий выше о newString.

EDIT: Чтобы ответить на ваш комментарий: Использование StringBuffer в порядке. То, что вы не может сделать, есть каждый decompress создать new StringBuffer, потому что тогда каждый раз, когда будет создан decompress, будет создан новый StringBuffer, который не то, что вы хотите. Если decompress принимает параметр StringBuffer newString, и каждый раз, когда decompress называет себя он проходит newString в качестве параметра, то каждый decompress вызова будет указывать на жеStringBuffer, так как это ссылка на объект.

Другой подход, который я думаю, что вы намекали на то, что поскольку decompress возвращает String, то каждый раз, когда decompress называет себя может использование результат функции (теперь ваш код просто выбросить), и, возможно, сцепить эта функция приводит к чему-то другому и возвращает новую строку. Я думаю, вы можете сделать этот подход работать, но я не изучил его полностью.

+0

Спасибо, я исправил его и опубликую обновленный код. Можете ли вы продолжить расширение newString и рекурсивную процедуру? Как мне это сделать? Могу ли я просто изменить его, и этот строковый буфер будет нормальным String, и я его конкатенирую. – CameronCarter

+0

@ user3003741 см. Мое редактирование. – ajb