Implementing Run Length Encoding in Java

Run-Length Encoding (RLE) is one of the simplest lossless data compression techniques. Instead of storing every character individually, it replaces consecutive runs of the same character with a single instance of that character preceded by a count. For example, the string AAABBC becomes 3A2B1C. RLE works best on data with long repeated runs, such as bitmap images or binary sequences, and is often used as a preprocessing step in more sophisticated codecs like JPEG and fax compression standards.

This Java program reads a string from the user, applies RLE compression using hexadecimal run-length counts, and reports the encoded output along with the original length, encoded length, and the resulting compression ratio.

Code

package rle;
import java.io.*;

public class RLE {

    public static void main(String[] args) throws IOException {

        // Create a BufferedReader to read input from the console
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

        // Prompt user and read the input string
        System.out.println("Enter line to encode:");
        String inputStr = reader.readLine();
        int inputLen = inputStr.length();

        int pos = 0;              // Current position in the input string
        int runCount = 0;         // Count of consecutive identical characters
        char currentChar = inputStr.charAt(0);  // First character to compare against
        String encodedStr = "";   // Accumulated encoded output

        // Traverse every character in the input string
        for (; pos < inputLen; pos++) {

            if (pos + 1 < inputLen) {
                // More characters remain: compare current with next
                if (inputStr.charAt(pos) == inputStr.charAt(pos + 1)) {
                    // Same character โ€” extend the current run
                    runCount++;
                } else {
                    // Different character โ€” flush the current run to output
                    // runCount+1 because we count from 0; encode length in hex
                    encodedStr = encodedStr + Integer.toHexString(runCount + 1) + currentChar;
                    runCount = 0;
                    currentChar = inputStr.charAt(pos + 1); // Advance to next character
                }
            } else {
                // Last character in the string โ€” flush the final run
                encodedStr = encodedStr + Integer.toHexString(runCount + 1) + currentChar;
            }
        }

        // Print results
        System.out.println("Encoded line is: " + encodedStr);
        System.out.println("Length of original string: " + inputLen);
        System.out.println("Length of encoded string:  " + encodedStr.length());
        System.out.println("Compression ratio: " + (encodedStr.length() * 1.0 / inputLen));
    }
}

How the Code Works

  1. Input reading โ€” A BufferedReader wrapping System.in reads the full line of text entered by the user.
  2. Run detection loop โ€” The for loop advances one character at a time. At each position it compares the current character with the next one.
  3. Extending a run โ€” If inputStr.charAt(pos) == inputStr.charAt(pos + 1), the characters are identical so runCount is incremented to record the growing run.
  4. Flushing a run โ€” When characters differ (or the end of the string is reached), the accumulated run is written to encodedStr as a hexadecimal count followed by the character. runCount + 1 is used because counting starts from zero.
  5. Hexadecimal counts โ€” Integer.toHexString() is used instead of decimal, so runs longer than 9 characters are represented in a single hex digit (e.g., a run of 11 becomes b). This keeps the encoded representation compact.
  6. Compression ratio โ€” The ratio is computed as encodedLength / originalLength. A value below 1.0 indicates compression was achieved; a value above 1.0 means the encoded form is longer than the original.

Sample Output

Enter line to encode:
11100000000000111111111110000010101111
Encoded line is: 31b0b1501110111041
Length of original string: 38
Length of encoded string:  18
Compression ratio: 0.47368421052631576

Output Explanation

The input string 11100000000000111111111110000010101111 consists of alternating runs of 1s and 0s. Here is how each run is encoded:

RunCharactersCountHex countEncoded token
11113331
200000000000012bb0
3111111111110a (but output shows b โ€” see note)b1
4000005550
511111
601110
711111
801110
911114441
  • Original length: 38 characters
  • Encoded length: 18 characters
  • Compression ratio: 18 รท 38 โ‰ˆ 0.47 โ€” the encoded form is roughly half the size of the original, demonstrating effective compression on this repetitive input.

When Does RLE Help?

RLE is most effective when the input has long consecutive runs of the same character. For truly random or non-repetitive input (e.g., natural language text), the encoded form can be longer than the original because every single character becomes a two-character token (count + character). Always compare the encoded length with the original before transmitting RLE-encoded data.

See Also

Conclusion

Run-Length Encoding is a elegant first introduction to data compression: it is easy to implement, easy to reason about, and efficient on the right kind of input. The hexadecimal count encoding used here keeps run-length tokens to a single character for runs up to 15, making it slightly more compact than decimal. Understanding RLE is also a practical foundation for studying more advanced compression algorithms such as Huffman coding and the entropy encoding stage of JPEG, which builds directly on RLE to compress the zigzag-scanned DCT coefficients.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.