4

I'm having slight trouble trying to compress a string using recursion.

For example, consider the following string:

qwwwwwwwwweeeeerrtyyyyyqqqqwEErTTT

After applying the RLE algorithm, this string is converted into:

q9w5e2rt5y4qw2Er3T

In the compressed string, "9w" represents a sequence of 9 consecutive lowercase "w" characters. "5e" represents 5 consecutive lowercase "e" characters, etc.

I already have a code for compressing it without recursion:

import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Compress {

    public static String input(String source) {
        StringBuffer coding = new StringBuffer();
        for (int i = 0; i < source.length(); i++) {
            int runLength = 1;
            while (i+1 < source.length() && source.charAt(i) == source.charAt(i+1)) {

                runLength++;   

                i++;

           }
            if (runLength>1){
            coding.append(runLength);
            }
            coding.append(source.charAt(i));
        }
        return coding.toString();
    }

    public static void main(String[] args) {

        IO.outputStringAnswer("Enter a string");
        String str = IO.readString();
        String result = ""; 
        result=input(str); //function(variable)


        IO.outputStringAnswer(result);
    }
}

But I am unsure if this is able to be turned into a recursion version of this.

Henry Florence
  • 2,848
  • 19
  • 16
AChoi
  • 57
  • 1
  • 2
  • 3
    You certainly *can* make a recursive version of it, but there's no clear benefit to doing so. – Jim Mischel Nov 25 '13 at 19:16
  • Oh, so I would have to rewrite the whole code? I'm still new to all this so I'm not very used to writing codes with recursion yet, sadly. – AChoi Nov 25 '13 at 19:19
  • 3
    Why do you want to compress a string using recursion? I am having a hard time seeing a reason for doing so - at least in Java. – Vegard Nov 25 '13 at 19:27
  • Oh it's part of an assignment I need to complete but I've never really used recursion in an assignment before until now. I've looked up some examples but I can't seem to figure out how to get recursion to be used for compression. – AChoi Nov 25 '13 at 19:29
  • 1
    Does the assignment provide any guidance or justification for using recursion? This seems like a really bad use of recursion. – Jim Garrison Nov 25 '13 at 19:34
  • Oh wow, I completely read the assignment wrong haha. They provided me a method file so I just need to complete that. I think I have the general idea of what to do now, thank you for the comments though ^^ – AChoi Nov 25 '13 at 19:44
  • just curious.. Why is regex among the labels.. – Ank Nov 25 '13 at 21:20

2 Answers2

4

This is most likely what you are looking for:

public static String compress(String source) {
    if (source.length() <= 1) return source;

    int runLength = 1;
    while (runLength < source.length() && source.charAt(0) == source.charAt(runLength)) {
        runLength++;
    }

    String lengthString = runLength > 1 ? String.valueOf(runLength) : "";
    return lengthString + source.substring(0,1) + compress(source.substring(runLength));
}

I assume your source String does not contain any digits. As you can see the function calls itself recursively in the last line with the remainder of the source string.

lex82
  • 11,173
  • 2
  • 44
  • 69
3

This is an interesting question. One solution that uses no iteration at all, only recursion would be:

public static String compressRecursion(String str, char curChar, int curCount) {
    // termination case - reached end of the source string
    if(str.length() == 0)
        return "" + (curCount == 1 ? "" : curCount) + curChar;

    // branch on change in next character
    String nextStr = str.substring(1,str.length());
    if(str.charAt(0) == curChar)
        return compressRecursion(nextStr,curChar,curCount + 1);
    else
        return "" + (curCount == 1 ? "" : curCount) + curChar
                + compressRecursion(nextStr,str.charAt(0),1);
}
public static String compress(String source) {
    return compressRecursion(source, source.charAt(0), 0);
}

This probably wouldn't be much use in production code, as a 'Stack Overflow' exception will occur with an input of any reasonable length, this is because a new stack frame will be created for every function call and thus character in the input. Java is not really designed to run code like this.

A synonymous compress function written in scheme (which has no iteration constructs):

(define (num2str num)
  (if (= 1 num) "" (number->string num)))

(define (first-char str)
  (substring str 0 1))

(define (next-string str)
  (substring str 1 (string-length str)))

(define (compress str char count)
  (cond [(= 0 (string-length str)) (string-append (num2str count) char)]
        [(string=? char (first-char str))
          (compress (next-string str) char (+ count 1))]
        [ else 
          (string-append (num2str count) char
            (compress (next-string str) (first-char str) 1))]))

(define (compressStart str)
  (compress str (first-char str) 0)) 

A functional language like scheme will use tail recursion optimisation to prevent stack overflow,and makes a function call a much more lightweight operation than in an imperative language like Java.

Henry Florence
  • 2,848
  • 19
  • 16