当前位置:首页算法 > 正文

哈夫曼编码的算法实现基于以下策略:

作者:野牛程序员:2023-05-24 15:05:57算法阅读 2450

哈夫曼编码的算法实现基于以下策略:

  1. 统计字符频率:首先需要对待编码的数据进行字符频率统计,确定每个字符出现的频率。

  2. 构建哈夫曼树:根据字符频率,构建哈夫曼树。算法开始时,每个字符都被看作是一个独立的树节点。然后,根据频率选择两个频率最低的节点,将它们合并为一个新的节点,并将新节点的频率设置为这两个节点的频率之和。这个过程会不断重复,直到所有的节点都合并为一棵完整的哈夫曼树。

  3. 分配编码:在哈夫曼树构建完成后,通过遍历哈夫曼树的路径,为每个字符分配唯一的二进制编码。当遍历到左子树时,标记为0,遍历到右子树时,标记为1。根据字符在哈夫曼树上的路径,即可得到对应的编码。

  4. 生成哈夫曼编码表:将每个字符与其对应的编码建立映射关系,生成哈夫曼编码表。

  5. 进行编码压缩:将原始数据中的每个字符,用其对应的哈夫曼编码替换,并将这些编码拼接成为一个串,即为压缩后的数据。

  6. 进行解码:使用生成的哈夫曼编码表,将压缩后的数据解码还原为原始数据。从根节点开始,依次读取压缩数据中的每个比特,根据编码表找到对应的字符,直到解码完所有的比特,即可得到原始数据。

通过以上策略,哈夫曼编码能够实现对数据的高效压缩和解压缩。

#include <iostream>
#include <queue>
#include <map>

using namespace std;

// 哈夫曼树节点
struct HuffmanNode {
    char data;
    int frequency;
    HuffmanNode *left, *right;

    HuffmanNode(char data, int frequency) {
        this->data = data;
        this->frequency = frequency;
        left = right = NULL;
    }
};

// 用于构建最小堆的比较器
struct Compare {
    bool operator()(HuffmanNode* a, HuffmanNode* b) {
        return a->frequency > b->frequency;
    }
};

// 递归构建哈夫曼树
HuffmanNode* buildHuffmanTree(map<char, int>& frequencyTable) {
    priority_queue<HuffmanNode*, vector<HuffmanNode*>, Compare> minHeap;

    // 将字符频率表中的字符转换为节点并加入最小堆
    for (map<char, int>::iterator it = frequencyTable.begin(); it != frequencyTable.end(); ++it) {
        HuffmanNode* node = new HuffmanNode(it->first, it->second);
        minHeap.push(node);
    }

    // 通过合并最小频率的节点构建哈夫曼树
    while (minHeap.size() > 1) {
        HuffmanNode* left = minHeap.top();
        minHeap.pop();

        HuffmanNode* right = minHeap.top();
        minHeap.pop();

        // 创建新节点,频率为左右子节点频率之和
        HuffmanNode* newNode = new HuffmanNode('$', left->frequency + right->frequency);
        newNode->left = left;
        newNode->right = right;

        minHeap.push(newNode);
    }

    // 返回哈夫曼树的根节点
    return minHeap.top();
}

// 递归生成哈夫曼编码表
void generateHuffmanCodes(HuffmanNode* root, string code, map<char, string>& huffmanCodes) {
    if (root == NULL) {
        return;
    }

    // 如果是叶节点,则将字符和对应的编码加入哈夫曼编码表
    if (root->left == NULL && root->right == NULL) {
        huffmanCodes[root->data] = code;
    }

    // 递归处理左右子树
    generateHuffmanCodes(root->left, code + "0", huffmanCodes);
    generateHuffmanCodes(root->right, code + "1", huffmanCodes);
}

// 哈夫曼编码压缩
string compress(string data) {
    map<char, int> frequencyTable;

    // 统计字符频率
    for (string::iterator it = data.begin(); it != data.end(); ++it) {
        frequencyTable[*it]++;
    }

    // 构建哈夫曼树
    HuffmanNode* root = buildHuffmanTree(frequencyTable);

    // 生成哈夫曼编码表
    map<char, string> huffmanCodes;
    generateHuffmanCodes(root, "", huffmanCodes);

    // 将原始数据编码压缩
    string compressedData;
    for (string::iterator it = data.begin(); it != data.end(); ++it) {
        compressedData += huffmanCodes[*it];
    }

    return compressedData;
}

// 哈夫曼解码
string decompress(string compressedData, HuffmanNode* root) {
    string decompressedData;
    HuffmanNode* current = root;

    for (string::iterator it = compressedData.begin(); it != compressedData.end(); ++it) {
        if (*it == '0') {
            current = current->left;
        } else {
            current = current->right;
        }

        // 如果到达叶节点,则将字符添加到解压后的数据中,并重置current为根节点
        if (current->left == NULL && current->right == NULL) {
            decompressedData += current->data;
            current = root;
        }
    }

    return decompressedData;
}

int main() {
    string data = "Hello, World!"; // 待压缩的数据

    // 进行压缩
    string compressedData = compress(data);
    cout << "Compressed Data: " << compressedData << endl;

    // 进行解压缩
    map<char, int> frequencyTable;
    for (string::iterator it = data.begin(); it != data.end(); ++it) {
        frequencyTable[*it]++;
    }
    HuffmanNode* root = buildHuffmanTree(frequencyTable);
    string decompressedData = decompress(compressedData, root);
    cout << "Decompressed Data: " << decompressedData << endl;

    return 0;
}

map<char, int>是C++标准库中的一个关联容器,它提供了一种将键值对进行关联的方式。在这里,char是键的类型,int是值的类型。

map是一个有序关联容器,它根据键的比较规则自动将键值对按键的升序进行排序。它使用红黑树(一种平衡二叉搜索树)作为底层实现,因此在插入、删除和查找操作上具有较高的效率。

在哈夫曼编码的例子中,map<char, int>用于构建字符频率表,其中的键为字符,值为对应字符出现的频率。通过统计原始数据中每个字符的频率,我们可以构建哈夫曼树和哈夫曼编码表。


野牛程序员教少儿编程与信息学奥赛-微信|电话:15892516892
野牛程序员教少儿编程与信息学竞赛-微信|电话:15892516892
相关推荐

最新推荐

热门点击