Welcome to collectivesolver - Programming & Software Q&A with code examples. A website with trusted programming answers. All programs are tested and work.

Contact: aviboots(AT)netvision.net.il

Semrush - keyword research tool

Turn ChatGPT, Claude, Gemini, And CoPilot Into Your Personal Assistant, Business Coach, Content Creator, And More

AFFILIATE MARKETING Your all-in-one performance engine Manage affiliates, creators, and customer referrals in one unified platform—turning every partnership into measurable growth
Secure & Reliable Web Hosting, Free Domain, Free SSL, 1-Click WordPress Install, Expert 24/7 Support

Boost your online presence with premium web hosting and servers

Disclosure: My content contains affiliate links.

42,844 questions

55,671 answers

573 users

How to perform high‑performance reversible text compression using a word dictionary in C++

1 Answer

0 votes
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
#include <cctype>
#include <sstream>

/*
    =====================================================================
    High‑Performance Reversible Text Compression Using a Word Dictionary
    ---------------------------------------------------------------------
    This program compresses text by replacing repeated words with tokens
    like @0, @1, @2... and stores each unique word in a dictionary.

    The compressed text is fully reversible.

    WHY THIS VERSION IS FAST (C++17):
    ---------------------------------
    • Uses std::unordered_map for O(1) average lookup.
    • Uses std::vector for compact dictionary storage.
    • Uses std::string_view for zero‑copy word extraction.
    • Uses std::string with reserve() to avoid reallocations.
    • Clean, idiomatic, modern C++ design.

    OUTPUT EXAMPLE:
        Original:   this is is a test test compression string string test
        Compressed: @0 @1 @1 @2 @3 @3 @4 @5 @5 @3
        Decompressed: this is is a test test compression string string test
    =====================================================================
*/


// ---------------------------------------------------------------------
// Dictionary structure: vector + hash table
// ---------------------------------------------------------------------
struct Dictionary {
    std::vector<std::string> words;                 // index → word
    std::unordered_map<std::string, int> indexMap;  // word → index
};


// ---------------------------------------------------------------------
// Find or add a word to the dictionary (O(1) average)
// ---------------------------------------------------------------------
int findOrAdd(Dictionary &dict, std::string_view word) {
    auto it = dict.indexMap.find(std::string(word));
    if (it != dict.indexMap.end())
        return it->second;

    int newIndex = dict.words.size();
    dict.words.emplace_back(word);
    dict.indexMap[dict.words.back()] = newIndex;
    
    return newIndex;
}


// ---------------------------------------------------------------------
// Compress text into @ID tokens
// ---------------------------------------------------------------------
std::string compress(const std::string &input, Dictionary &dict) {
    std::string output;
    output.reserve(input.size() * 2); // avoid reallocations

    size_t i = 0;
    while (i < input.size()) {

        // Pass punctuation/spaces directly
        if (!std::isalnum(static_cast<unsigned char>(input[i]))) {
            output.push_back(input[i]);
            i++;
            continue;
        }

        // Extract word
        size_t start = i;
        while (i < input.size() && std::isalnum(static_cast<unsigned char>(input[i])))
            i++;

        std::string_view word(&input[start], i - start);

        // Get dictionary index
        int id = findOrAdd(dict, word);

        // Write token
        output += '@';
        output += std::to_string(id);
    }

    return output;
}


// ---------------------------------------------------------------------
// Decompress @ID tokens back into original text
// ---------------------------------------------------------------------
std::string decompress(const std::string &compressed, const Dictionary &dict) {
    std::string output;
    output.reserve(compressed.size() * 2);

    size_t i = 0;
    while (i < compressed.size()) {

        // Token?
        if (compressed[i] == '@') {
            i++;

            int id = 0;
            while (i < compressed.size() && std::isdigit(static_cast<unsigned char>(compressed[i]))) {
                id = id * 10 + (compressed[i] - '0');
                i++;
            }

            if (id >= 0 && id < static_cast<int>(dict.words.size())) {
                output += dict.words[id];
            }
        }
        else {
            // Pass punctuation/spaces
            output.push_back(compressed[i]);
            i++;
        }
    }

    return output;
}


// ---------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------
int main() {
    std::string original =
        "this is is a test test compression string string test this is a test compression";

    Dictionary dict;

    std::string compressed = compress(original, dict);
    std::string decompressed = decompress(compressed, dict);

    std::cout << "Original:      \"" << original << "\"\n";
    std::cout << "Compressed:    \"" << compressed << "\"\n";
    std::cout << "Decompressed:  \"" << decompressed << "\"\n\n";

    std::cout << "Dictionary:\n";
    for (size_t i = 0; i < dict.words.size(); i++)
        std::cout << "  @" << i << " => " << dict.words[i] << "\n";
}



/*
run:

Original:      "this is is a test test compression string string test this is a test compression"
Compressed:    "@0 @1 @1 @2 @3 @3 @4 @5 @5 @3 @0 @1 @2 @3 @4"
Decompressed:  "this is is a test test compression string string test this is a test compression"

Dictionary:
  @0 => this
  @1 => is
  @2 => a
  @3 => test
  @4 => compression
  @5 => string

*/

 



answered Jul 31 by avibootz

Related questions

...