KompressionCMP-01
Lauflängenkodierung (RLE)
Statt zwölfmal W zu speichern, merkt man sich einfach: zwölfmal W.
- Laufzeit
- O(n)
- Zusatzspeicher
- O(n)
- Verlustfrei
- ja
- Schlechtester Fall
- doppelte Größe
01Worum es geht
Die Lauflängenkodierung ist die einfachste Form von Kompression, die es gibt. Sie ersetzt jede Folge gleicher Zeichen durch die Anzahl und das Zeichen: Aus WWWWWWWWWWWWB wird 12W1B.
Verlustfrei ist sie dabei immer, das Original lässt sich exakt zurückgewinnen. Sie lohnt sich aber nur, wenn es lange Wiederholungen gibt: bei Schwarzweißbildern, Faxen, einfachen Pixelgrafiken oder Sensordaten, die sich selten ändern.
02So funktioniert es
Kodieren läuft einmal durch die Eingabe:
- Merke dir das aktuelle Zeichen.
- Zähle, wie oft es sich unmittelbar wiederholt.
- Schreibe Anzahl und Zeichen in die Ausgabe und springe hinter die gezählte Folge.
Dekodieren ist der Weg zurück. Da eine Anzahl mehrere Ziffern haben kann, werden erst alle Ziffern gelesen, bis ein Zeichen auftaucht. Das Zeichen wird dann so oft ausgegeben, wie die Zahl es angibt.
Beide Richtungen sehen jedes Zeichen genau einmal an, deshalb ist der Aufwand linear.
03Implementierung
using System.Text;
public static class RunLengthEncoding
{
// Ersetzt jede Folge gleicher Zeichen durch "Anzahl + Zeichen": aus "aaab" wird "3a1b".
public static string Encode(string input)
{
var result = new StringBuilder();
var index = 0;
while (index < input.Length)
{
var current = input[index];
var runLength = 1;
// Zählen, wie oft sich das aktuelle Zeichen hier wiederholt.
while (index + runLength < input.Length && input[index + runLength] == current)
runLength++;
result.Append(runLength).Append(current);
index += runLength;
}
return result.ToString();
}
// Macht aus "3a1b" wieder "aaab".
public static string Decode(string encoded)
{
var result = new StringBuilder();
var index = 0;
while (index < encoded.Length)
{
// Eine Anzahl kann mehrere Ziffern haben, also Ziffern lesen, bis ein Zeichen auftaucht.
var digits = 0;
while (char.IsDigit(encoded[index + digits]))
digits++;
var count = int.Parse(encoded.AsSpan(index, digits));
result.Append(encoded[index + digits], count);
index += digits + 1;
}
return result.ToString();
}
}
04Beispiel
var input = "WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB";
var encoded = RunLengthEncoding.Encode(input);
Console.WriteLine(encoded);
// Kürzer als die Eingabe - aber nur, weil sie lange Wiederholungen enthält.
Console.WriteLine($"{input.Length} -> {encoded.Length} characters");
Console.WriteLine(RunLengthEncoding.Decode(encoded) == input);
12W1B12W3B24W1B
53 -> 15 characters
True
05Gut zu wissen
- Im schlechtesten Fall wird das Ergebnis doppelt so groß wie die Eingabe, nämlich wenn sich kein einziges Zeichen wiederholt. Aus
abcwird1a1b1c. - Deshalb schreiben echte Formate die Anzahl nur bei Wiederholungen und markieren sonst unkomprimierte Blöcke. Genau das macht zum Beispiel PackBits in TIFF-Dateien.
- Enthält die Eingabe selbst Ziffern, ist dieses einfache Format mehrdeutig. In der Praxis kodiert man deshalb Bytes mit einer festen Längenangabe statt Text.