• Huffman算法


    介绍

    求解最优二叉树问题通常使用动态规划算法中的一种称为"Huffman算法"或者"Huffman编码"。

    Huffman算法的基本思想:

    根据节点的频率或者权重构建一棵最优二叉树。最小频率的节点会被放置在树的底部,而较大频率的节点则放置在较高的位置,以此最大限度地减少树的平均路径长度。

    具体步骤如下:
    1. 首先,统计所有节点的频率或者权重,并按照频率或者权重对节点进行排序。
    2. 创建一个包含所有节点的森林(由单个节点组成的树)。
    3. 从森林中选择两个具有最小频率或者权重的节点,并创建一个新的父节点,频率或者权重等于这两个节点的频率或者权重之和。
    4. 将这两个节点作为新节点的左右子节点,并将新节点加入到森林中。
    5. 重复步骤3和步骤4,直到森林中只剩下一个节点,即最优二叉树的根节点。
    6. 最后,对最优二叉树进行编码,将频率或者权重较大的节点赋予较短的编码,而频率或者权重较小的节点赋予较长的编码。

    Huffman算法的时间复杂度主要取决于对节点进行排序的部分,通常使用的排序算法是堆排序或者快速排序,时间复杂度为O(nlogn),其中n为节点的数量。

    总结一下,Huffman算法是一种用于构建最优二叉树的动态规划算法,它通过选择频率或者权重最小的节点来构建树,以最小化树的平均路径长度。

    举例

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. // Huffman树节点
    6. struct HuffmanNode {
    7. char data; // 符号(字符)
    8. int frequency; // 频率
    9. HuffmanNode* left;
    10. HuffmanNode* right;
    11. HuffmanNode(char d, int freq) : data(d), frequency(freq), left(nullptr), right(nullptr) {}
    12. };
    13. // 比较函数(按照频率从小到大排序)
    14. struct Compare {
    15. bool operator()(const HuffmanNode* a, const HuffmanNode* b) {
    16. return a->frequency > b->frequency;
    17. }
    18. };
    19. // 构建Huffman树
    20. HuffmanNode* buildHuffmanTree(const unordered_map<char, int>& freqMap) {
    21. // 创建小顶堆,用于选择频率最小的节点
    22. priority_queue, Compare> minHeap;
    23. // 创建叶子节点,并将其加入到小顶堆中
    24. for (const auto& entry : freqMap) {
    25. HuffmanNode* node = new HuffmanNode(entry.first, entry.second);
    26. minHeap.push(node);
    27. }
    28. // 构建Huffman树(合并节点)
    29. while (minHeap.size() > 1) {
    30. // 选择频率最小的两个节点
    31. HuffmanNode* leftNode = minHeap.top();
    32. minHeap.pop();
    33. HuffmanNode* rightNode = minHeap.top();
    34. minHeap.pop();
    35. // 创建新节点,频率为子节点频率之和
    36. HuffmanNode* newNode = new HuffmanNode('$', leftNode->frequency + rightNode->frequency);
    37. newNode->left = leftNode;
    38. newNode->right = rightNode;
    39. // 将新节点加入到小顶堆中
    40. minHeap.push(newNode);
    41. }
    42. // 返回Huffman树的根节点
    43. return minHeap.top();
    44. }
    45. // 生成Huffman编码
    46. void generateHuffmanCodes(HuffmanNode* root, string code, unordered_map<char, string>& huffmanCodes) {
    47. if (root == nullptr) {
    48. return;
    49. }
    50. // 叶子节点表示一个字符,将其编码加入到map中
    51. if (root->left == nullptr && root->right == nullptr) {
    52. huffmanCodes[root->data] = code;
    53. }
    54. // 递归生成左子树和右子树的编码
    55. generateHuffmanCodes(root->left, code + "0", huffmanCodes);
    56. generateHuffmanCodes(root->right, code + "1", huffmanCodes);
    57. }
    58. // 压缩数据
    59. string compressData(const string& data, const unordered_map<char, string>& huffmanCodes) {
    60. string compressedData = "";
    61. // 遍历原始数据,将字符替换为对应的Huffman编码
    62. for (char c : data) {
    63. compressedData += huffmanCodes.at(c);
    64. }
    65. return compressedData;
    66. }
    67. // 解压缩数据
    68. string decompressData(const string& compressedData, HuffmanNode* root) {
    69. string decompressedData = "";
    70. HuffmanNode* current = root;
    71. // 遍历压缩后的数据,根据Huffman编码逐个恢复原始字符
    72. for (char c : compressedData) {
    73. if (c == '0') {
    74. current = current->left;
    75. } else {
    76. current = current->right;
    77. }
    78. // 到达叶子节点,表示找到一个字符
    79. if (current->left == nullptr && current->right == nullptr) {
    80. decompressedData += current->data;
    81. current = root; // 恢复到根节点以继续下一个字符的解压缩
    82. }
    83. }
    84. return decompressedData;
    85. }
    86. int main() {
    87. string data = "hello huffman!";
    88. unordered_map<char, int> freqMap;
    89. // 统计字符频率
    90. for (char c : data) {
    91. freqMap[c]++; // 字符已存在,则自增; 否则, 创建新键值对
    92. }
    93. // 构建Huffman树
    94. HuffmanNode* root = buildHuffmanTree(freqMap);
    95. // 生成Huffman编码
    96. unordered_map<char, string> huffmanCodes;
    97. generateHuffmanCodes(root, "", huffmanCodes);
    98. // 输出Huffman编码
    99. cout << "Huffman Codes:" << endl;

  • 相关阅读:
    Nanoprobes FluoroNanogold 偶联物的特色和应用
    java版 Spring Cloud+uniapp b2b2c o2o 多商家入驻商城 直播带货商城 电子商务
    HTML5期末大作业:基于 html css js仿腾讯课堂首页
    蓝桥等考Python组别五级003
    OOP | 封装 继承 多态
    基于Echarts实现可视化数据大屏电子商务公共服务平台大数据中心
    远程debug调试
    Java I/O(二)BIO, NIO, AIO
    蓝桥等考Python组别十八级004
    Fedora 35 部署DNS主从和分离解析 —— 筑梦之路
  • 原文地址:https://blog.csdn.net/m0_63024355/article/details/133909159