How to resolve the algorithm LZW compression step by step in the C# programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm LZW compression step by step in the C# programming language

Table of Contents

Problem Statement

The Lempel-Ziv-Welch (LZW) algorithm provides loss-less data compression. You can read a complete description of it in the   Wikipedia article   on the subject.   It was patented, but it entered the public domain in 2004.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm LZW compression step by step in the C# programming language

LZW Compression and Decompression Algorithm

Objective:

  • Compresses and decompresses strings using the Lempel-Ziv-Welch (LZW) algorithm.

Compression Process (Compress method):

  1. Initialize Dictionary: Create a dictionary containing the ASCII values (0-255) mapped to their corresponding single-character strings.
  2. Initialize Variables: w: empty string, compressed: list of compressed integers.
  3. Loop through the input string:
    • wc: concatenate w and the current character.
    • If wc is in the dictionary: w = wc, continue looping.
    • Otherwise:
      • Add w to the dictionary with the next available index.
      • Add the dictionary index of w to compressed.
      • w = current character, continue looping.
  4. Finish Compression: Add the remaining w to the compressed list if it's not empty.

Decompression Process (Decompress method):

  1. Initialize Dictionary: Same as compression.
  2. Initialize Variables: w: first value in the compressed list, decompressed: string builder.
  3. Remove the first value from compressed: It's the index of the first character.
  4. Loop through the compressed list:
    • entry: dictionary value corresponding to the current index.
    • If the current index is not in the dictionary: entry = w + w[0].
    • Append entry to decompressed.
    • Add w + entry[0] to the dictionary with the next available index.
    • w = entry, continue looping.

Example:

  • Input String: "TOBEORNOTTOBEORTOBEORNOT"
  • Compressed List: [20, 97, 38, 71, 38, 15, 18, 79, 18, 15]
  • Decompressed String: "TOBEORNOTTOBEORTOBEORNOT"

Additional Notes:

  • The LZW algorithm uses variable-length codes, which allows it to achieve better compression ratios compared to fixed-length codes (e.g., Huffman coding).
  • The dictionary grows dynamically during both compression and decompression, allowing for the efficient handling of repetitive sequences in the input.
  • The algorithm is not lossless, meaning it may introduce slight changes in the decompressed output compared to the original input.

Source code in the csharp programming language

using System;
using System.Collections.Generic;
using System.Text;

namespace LZW
{
    public class Program
    {
        public static void Main(string[] args)
        {
            List<int> compressed = Compress("TOBEORNOTTOBEORTOBEORNOT");
            Console.WriteLine(string.Join(", ", compressed));
            string decompressed = Decompress(compressed);
            Console.WriteLine(decompressed);
        }

        public static List<int> Compress(string uncompressed)
        {
            // build the dictionary
            Dictionary<string, int> dictionary = new Dictionary<string, int>();
            for (int i = 0; i < 256; i++)
                dictionary.Add(((char)i).ToString(), i);

            string w = string.Empty;
            List<int> compressed = new List<int>();

            foreach (char c in uncompressed)
            {
                string wc = w + c;
                if (dictionary.ContainsKey(wc))
                {
                    w = wc;
                }
                else
                {
                    // write w to output
                    compressed.Add(dictionary[w]);
                    // wc is a new sequence; add it to the dictionary
                    dictionary.Add(wc, dictionary.Count);
                    w = c.ToString();
                }
            }

            // write remaining output if necessary
            if (!string.IsNullOrEmpty(w))
                compressed.Add(dictionary[w]);

            return compressed;
        }

        public static string Decompress(List<int> compressed)
        {
            // build the dictionary
            Dictionary<int, string> dictionary = new Dictionary<int, string>();
            for (int i = 0; i < 256; i++)
                dictionary.Add(i, ((char)i).ToString());

            string w = dictionary[compressed[0]];
            compressed.RemoveAt(0);
            StringBuilder decompressed = new StringBuilder(w);

            foreach (int k in compressed)
            {
                string entry = null;
                if (dictionary.ContainsKey(k))
                    entry = dictionary[k];
                else if (k == dictionary.Count)
                    entry = w + w[0];

                decompressed.Append(entry);

                // new sequence; add it to the dictionary
                dictionary.Add(dictionary.Count, w + entry[0]);

                w = entry;
            }

            return decompressed.ToString();
        }
    }
}

  

You may also check:How to resolve the algorithm Loops/Foreach step by step in the Nim programming language
You may also check:How to resolve the algorithm Smith numbers step by step in the Tcl programming language
You may also check:How to resolve the algorithm Jewels and stones step by step in the Perl programming language
You may also check:How to resolve the algorithm Monte Carlo methods step by step in the Ada programming language
You may also check:How to resolve the algorithm Table creation/Postal addresses step by step in the Sidef programming language