c语言编程笔录

首页 > C语言 > c语言

c语言

C++实现Huffman的编解码

更新时间:2023-08-09

引言:

Huffman编码是一种用于数据压缩的算法,它通过将出现频率高的字符用较短的编码表示,而出现频率低的字符用较长的编码表示,从而实现数据的高效压缩。在C++中实现Huffman编解码算法,可以通过构建Huffman树来实现。Huffman树是一种特殊的二叉树,它的每个非叶子节点都有两个子节点,且每个叶子节点都表示一个字符。

在实现Huffman编解码的过程中,通常需要实现以下几个功能:1. 统计字符出现频率;2. 构建Huffman树;3. 生成字符的编码表;4. 对原始数据进行编码;5. 对编码数据进行解码。接下来我们将对这些功能逐一进行详细介绍和解释。

1. 统计字符出现频率:

在Huffman编码中,我们需要先统计字符在原始数据中出现的频率,以确定哪些字符出现的较为频繁。可以使用一个数组或者哈希表来记录每个字符的频率。遍历原始数据,对应字符的频率加一即可。

// 统计字符频率
std::unordered_map countFrequencies(const std::string& data) {
    std::unordered_map frequencies;
    for (char c : data) {
        frequencies[c]++;
    }
    return frequencies;
}

2. 构建Huffman树:

构建Huffman树是实现Huffman编码的关键步骤。可以使用优先队列(priority queue)来构建Huffman树。首先,将每个字符和其对应的频率作为叶子节点,并将它们插入优先队列。接着,从优先队列中取出两个频率最小的节点(可以通过自定义比较函数来实现,频率较小的排在前面),将它们作为子节点构建一个新的父节点,并将父节点的频率设置为两个子节点的频率之和。然后,将新的父节点插入优先队列中。重复以上步骤,直到优先队列中只剩下一个节点,该节点就是Huffman树的根节点。

// Huffman树节点
struct Node {
    char data;
    int frequency;
    Node* left;
    Node* right;
    ...
};

// 构建Huffman树
Node* buildHuffmanTree(const std::unordered_map& frequencies) {
    auto compare = [](const Node* a, const Node* b) {
        return a->frequency > b->frequency;
    };
    std::priority_queue, decltype(compare)> pq(compare);

    // 创建叶子节点并插入优先队列
    for (const auto& pair : frequencies) {
        Node* leaf = new Node{pair.first, pair.second, nullptr, nullptr};
        pq.push(leaf);
    }

    // 构建Huffman树
    while (pq.size() > 1) {
        Node* left = pq.top();
        pq.pop();
        Node* right = pq.top();
        pq.pop();

        Node* parent = new Node{'\0', left->frequency + right->frequency, left, right};
        pq.push(parent);
    }

    Node* root = pq.top();
    pq.pop();
    return root;
}

3. 生成字符的编码表:

生成字符的编码表是为了将字符映射到相应的Huffman编码。可以通过深度优先遍历Huffman树来实现。从树的根节点开始,沿着左子树路径为'0',沿着右子树路径为'1',将编码添加到对应的字符上。遍历到叶子节点时,就得到了叶子节点对应的Huffman编码。

// 生成编码表
void generateCodeTable(const Node* root, const std::string& code, std::unordered_map& codeTable) {
    if (root->left == nullptr && root->right == nullptr) {
        codeTable[root->data] = code;
        return;
    }
    generateCodeTable(root->left, code + "0", codeTable);
    generateCodeTable(root->right, code + "1", codeTable);
}

4. 对原始数据进行编码:

根据生成的编码表,可以将原始数据中的字符逐个替换为对应的Huffman编码。编码后的数据可以进一步进行压缩,因为Huffman编码使用较短的二进制串来表示较频繁出现的字符。

// Huffman编码
std::string encodeData(const std::string& data, const std::unordered_map& codeTable) {
    std::string encodedData;
    for (char c : data) {
        encodedData += codeTable.at(c);
    }
    return encodedData;
}

5. 对编码数据进行解码:

对编码数据进行解码的过程,是根据Huffman树的结构逆向进行的。从Huffman树的根节点开始,遍历编码数据的每一位,如果是'0',则沿着左子树路径向下,如果是'1',则沿着右子树路径向下,直到到达叶子节点,此时就找到了对应的字符。

// Huffman解码
std::string decodeData(const std::string& encodedData, const Node* root) {
    std::string decodedData;
    const Node* node = root;
    for (char bit : encodedData) {
        if (bit == '0') {
            node = node->left;
        } else if (bit == '1') {
            node = node->right;
        }
        if (node->left == nullptr && node->right == nullptr) {
            decodedData += node->data;
            node = root;
        }
    }
    return decodedData;
}

总结:

通过采用C++语言实现Huffman编解码算法,我们可以实现对数据的高效压缩和解压缩。通过统计字符出现的频率,构建Huffman树,生成编码表,并对原始数据进行编码和解码,我们可以得到编码后的数据,并能够将其还原为原始数据。这种基于Huffman编码的数据压缩算法在实际应用中具有广泛的使用场景。