当前位置:   article > 正文

趣学算法-贪心算法: Huffman编码_哈夫曼编码 贪心算法

哈夫曼编码 贪心算法

 Huffman编码的原理:

以字符的使用频率作为权构建一棵哈夫曼树,然后利用哈夫曼树对字符进行编码。构造一棵哈夫曼树,是将所要编码的字符作为叶子结点,该字符在文件中的使用频率作为叶子结点的权值,以“自底向上”的方式,通过n-1次“合并”运算后构造出的一棵树。

核心思想:权值越大的叶子离根越远。

贪心策略:每次从树的集合中取出没有双亲且权值最小的两棵树作为左右子树。

 

先构建一棵Huffman树:

(1)先找到权值最小且没有父亲的两个结点进行合并,创建一棵树,然后循环创建。

 

设置结构体:

  1. typedef struct{
  2. double weight;
  3. int parent;
  4. int lchild;
  5. int rchild;
  6. char value;
  7. } HNodeType;//节点结构体
  8. typedef struct{
  9. int bit[MAXBIT];
  10. int start;//反向存储,正向输出
  11. } HcodeType; //编码结构体
  12. HNodeType HuffNode[MAXNODE];
  13. HcodeType HuffCode[MAXLEAF];

 

初始化:

 

  1. int i,j;
  2. int x1, x2;//两个最小权值结点在数组中的序号
  3. double m1, m2;//两个最小权值结点的权值
  4. //初始化哈夫曼数组中的结点
  5. for(i = 0; i <= 2*n - 1; ++ i)
  6. {
  7. HuffNode[i].weight = 0;//权值
  8. HuffNode[i].parent = -1;
  9. HuffNode[i].lchild = -1;
  10. HuffNode[i].rchild = -1;
  11. }
  12. //输入n个叶子结点的名称和权值
  13. for(i = 0; i < n; ++i)
  14. {
  15. cout << "please input value and weight of leaf node:" << i +1;
  16. cin >> HuffNode[i].value >> HuffNode[i].weight;
  17. }

 

 构造Huffman树

  1. //构造Huffman树(核心)
  2. for(i = 0 ; i < n-1; ++i)
  3. {
  4. m1 = m2 = MAXVALUE;//初始化为最大值;
  5. x1 = x2 = -1;
  6. //找出所有结点中权值最小且无父亲的两个结点,并合并成一棵二叉树
  7. for(j = 0 ; j < n+i; ++j)
  8. {
  9. if(m1 > HuffNode[j].weight && HuffNode[j].parent == -1)
  10. {
  11. m2 = m1;
  12. x2 = x1;
  13. m1 = HuffNode[j].weight;
  14. x1 = j;
  15. }
  16. else if(m2 > HuffNode[j].weight && HuffNode[j].parent == -1)
  17. {
  18. m2 = HuffNode[j].weight;
  19. x2 = j;
  20. }
  21. }
  22. //设置找到的两个结点的父节点的信息
  23. HuffNode[n+i].weight = m1 + m2;
  24. HuffNode[n+i].lchild = x1;
  25. HuffNode[n+i].rchild = x2;
  26. HuffNode[x1].parent = n+i;
  27. HuffNode[x2].parent = n+i;
  28. cout << "x1.weight and x2.weight in round" << i+1 <<"\t"
  29. << HuffNode[x1].weight << "\t" << HuffNode[x2].weight << endl;
  30. }

 

 2. 输出哈夫曼编码

 

  1. void HuffmanCode(HcodeType HuffCode[MAXLEAF], int n)
  2. {
  3. HcodeType cd;//定义一个临时变量来存放求解编码时的信息
  4. int i,j,c,p;
  5. for(i = 0 ; i < n; ++ i)
  6. {
  7. cd.start = n-1;
  8. c = i;//c的编号
  9. p = HuffNode[c].parent;//c的父亲结点的编号
  10. while(p != -1)
  11. {
  12. if(HuffNode[p].lchild == c)
  13. cd.bit[cd.start] = 0;
  14. else if(HuffNode[p].rchild == c)
  15. cd.bit[cd.start] = 1;
  16. cd.start --;
  17. c = p;
  18. p = HuffNode[p].parent;
  19. }
  20. //把叶子结点的编码信息从临时编码cd复制出来,放入编码结构体数组
  21. for(j = cd.start+1; j < n; ++ j)
  22. HuffCode[i].bit[j] = cd.bit[j];
  23. HuffCode[i].start = cd.start;
  24. }
  25. }

 

 合并后的代码:

 

  1. #include<iostream>
  2. using namespace std;
  3. #define MAXBIT 100
  4. #define MAXVALUE 10000
  5. #define MAXLEAF 30
  6. #define MAXNODE MAXLEAF*2-1
  7. typedef struct{
  8. double weight;
  9. int parent;
  10. int lchild;
  11. int rchild;
  12. char value;
  13. } HNodeType;//节点结构体
  14. typedef struct{
  15. int bit[MAXBIT];
  16. int start;//反向存储,正向输出
  17. } HcodeType; //编码结构体
  18. HNodeType HuffNode[MAXNODE];
  19. HcodeType HuffCode[MAXLEAF];
  20. /* 构造哈夫曼树:先找到权值最小且无父亲的两个节点,合并成新的节点*/
  21. void HuffmanTree(HNodeType HuffNode[MAXNODE], int n)
  22. {
  23. int i,j;
  24. int x1, x2;//两个最小权值结点在数组中的序号
  25. double m1, m2;//两个最小权值结点的权值
  26. //初始化哈夫曼数组中的结点
  27. for(i = 0; i <= 2*n - 1; ++ i)
  28. {
  29. HuffNode[i].weight = 0;//权值
  30. HuffNode[i].parent = -1;
  31. HuffNode[i].lchild = -1;
  32. HuffNode[i].rchild = -1;
  33. }
  34. //输入n个叶子结点的名称和权值
  35. for(i = 0; i < n; ++i)
  36. {
  37. cout << "please input value and weight of leaf node:" << i +1;
  38. cin >> HuffNode[i].value >> HuffNode[i].weight;
  39. }
  40. //构造Huffman树(核心)
  41. for(i = 0 ; i < n-1; ++i)
  42. {
  43. m1 = m2 = MAXVALUE;//初始化为最大值;
  44. x1 = x2 = -1;
  45. //找出所有结点中权值最小且无父亲的两个结点,并合并成一棵二叉树
  46. for(j = 0 ; j < n+i; ++j)
  47. {
  48. if(m1 > HuffNode[j].weight && HuffNode[j].parent == -1)
  49. {
  50. m2 = m1;
  51. x2 = x1;
  52. m1 = HuffNode[j].weight;
  53. x1 = j;
  54. }
  55. else if(m2 > HuffNode[j].weight && HuffNode[j].parent == -1)
  56. {
  57. m2 = HuffNode[j].weight;
  58. x2 = j;
  59. }
  60. }
  61. //设置找到的两个结点的父节点的信息
  62. HuffNode[n+i].weight = m1 + m2;
  63. HuffNode[n+i].lchild = x1;
  64. HuffNode[n+i].rchild = x2;
  65. HuffNode[x1].parent = n+i;
  66. HuffNode[x2].parent = n+i;
  67. cout << "x1.weight and x2.weight in round" << i+1 <<"\t"
  68. << HuffNode[x1].weight << "\t" << HuffNode[x2].weight << endl;
  69. }
  70. }
  71. /*哈夫曼编码:从叶子结点开始,查看其是否有父亲结点,如果有,查看是其父亲结点的
  72. 左孩子还是右孩子,左孩子编码为0,右孩子编码为1*/
  73. void HuffmanCode(HcodeType HuffCode[MAXLEAF], int n)
  74. {
  75. HcodeType cd;//定义一个临时变量来存放求解编码时的信息
  76. int i,j,c,p;
  77. for(i = 0 ; i < n; ++ i)
  78. {
  79. cd.start = n-1;
  80. c = i;//c的编号
  81. p = HuffNode[c].parent;//c的父亲结点的编号
  82. while(p != -1)
  83. {
  84. if(HuffNode[p].lchild == c)
  85. cd.bit[cd.start] = 0;
  86. else if(HuffNode[p].rchild == c)
  87. cd.bit[cd.start] = 1;
  88. cd.start --;
  89. c = p;
  90. p = HuffNode[p].parent;
  91. }
  92. //把叶子结点的编码信息从临时编码cd复制出来,放入编码结构体数组
  93. for(j = cd.start+1; j < n; ++ j)
  94. HuffCode[i].bit[j] = cd.bit[j];
  95. HuffCode[i].start = cd.start;
  96. }
  97. }
  98. int main()
  99. {
  100. int i,j,n;
  101. cout << "please input n: " << endl;
  102. cin >> n;
  103. HuffmanTree(HuffNode,n);//构造哈夫曼树
  104. HuffmanCode(HuffCode,n);//哈夫曼树编码
  105. //输出已保存好的所有存在编码的哈夫曼编码(叶子节点编码)
  106. for(i = 0; i < n; ++i)
  107. {
  108. cout << HuffNode[i].value << ":Huffman code is:";
  109. for(j = HuffCode[i].start+1; j < n; ++j)
  110. cout << HuffCode[i].bit[j];
  111. cout << endl;
  112. }
  113. return 0;
  114. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/693635
推荐阅读
相关标签
  

闽ICP备14008679号