当前位置:   article > 正文

4.4--贪心--Huffman编码(哈夫曼编码)_贪心算法哈夫曼编码

贪心算法哈夫曼编码

Huffman编码的贪心算法体现在--总是合并最小频率的字符

哈夫曼编码简介

哈夫曼编码是广泛地用于数据文件压缩的十分有效的编码方法。其压缩率通常在20%~90%之间。

哈夫曼编码算法用字符在文件中出现的频率表来建立一个用0,1串表示各字符的最优表示方式。 

给出现频率高的字符较短的编码,出现频率较低的字符以较长的编码,可以大大缩短总码长。

1、前缀码:对每一个字符规定一个0,1串作为其代码,并要求任一字符的代码都不是其它字符代码的前缀。这种编码称为前缀码。编码的前缀性质可以使译码方法非常简单。表示最优前缀码的二叉树总是一棵完全二叉树,即树中任一结点都有2个儿子结点。树叶代表给定的字符,每一个字符的前缀码可以看做是从树根到代表该字符树叶的一条路,每一位0或者1分别作为指示的“路标”。

举个例子

 定长编码不是最优的,最优前缀码总是一颗满二叉树,给定编码字符集C中任意字符c以频率f(c)出现在数据文件中,d(c)是字符c的前缀码长,也就是说字符c在树T中的深度记为d(c),那么这个编码方案的平均码长是 sum( f(c) * d(c) )其中c是属于字符集C的一个字符。

2、构造哈夫曼编码 :哈夫曼提出构造最优前缀码的贪心算法,由此产生的编码方案称为哈夫曼编码。         

1)哈夫曼算法以自底向上的方式构造表示最优前缀码的二叉树T。         

2)算法以|C|个叶结点开始,执行|C|-1次的“合并”运算后产生最终所要求的树T。

3)假设编码字符集中每一字符c的频率是f(c)。以f为键值的优先队列Q用在贪心选择时有效地确定算法当前要合并的2棵具有最小频率的树。一旦2棵具有最小频率的树合并后,产生一棵新的树,其频率为合并的2棵树的频率之和,并将新树插入优先队列Q。经过n-1次的合并后,优先队列中只剩下一棵树,即所要求的树T。

构造过程如下图所示

算法描述

 Huffman算法首先用字符集C中每个字符c,频率为f(c),初始化优先队列Q。

然后不断地从优先队列Q中取出具有最小频率的两棵树x和y,将它们合并为一棵树z,z=x+y

新树z,左儿子是x,右儿子是y。经过n-1次的合并后,优先队列中只剩下一棵树,就是要求的最优Huffman编码树

时间分析

贪心选择性质

证明可以对T作适当修改后得到一棵新的二叉树T”,在T”中x和y是最深叶子且为兄弟,同时T”表示的前缀码也是C的最优前缀码。

设b和c是二叉树T的最深叶子,且为兄弟。

设f(b)<=f(c),f(x)<=f(y)。由于x和y是C中具有最小频率的两个字符,有f(x)<=f(b),f(y)<=f(c)。

首先,在树T中交换叶子b和x的位置得到T',然后再树T'中交换叶子c和y的位置,得到树T''。

 类似的,可以证明在T'中交换y与c的位置也不断增加平均码长,即B(T')-B(T'')也是非负。

由此可知,B(T'')<=B(T') <=B(T)

因此,T''表示的前缀码也是最优前缀码,且x,y具有相同的码长,同时,仅最优一位编码不同。

最优子结构性质

 代码:

main.cpp

  1. //4d4 贪心算法 哈夫曼算法
  2. //#include "stdafx.h"
  3. #include "BinaryTree.h"
  4. #include "MinHeap.h"
  5. #include <iostream>
  6. using namespace std;
  7. const int N = 6;
  8. template<class Type> class Huffman;
  9. template<class Type>
  10. BinaryTree<int> HuffmanTree(Type f[],int n);
  11. template<class Type>
  12. class Huffman
  13. {
  14. friend BinaryTree<int> HuffmanTree(Type[],int n);
  15. public:
  16. operator Type() const
  17. {
  18. return weight;
  19. }
  20. //private:
  21. BinaryTree<int> tree;
  22. Type weight;
  23. };
  24. int main()
  25. {
  26. char c[] = {'0','a','b','c','d','e','f'};
  27. int f[] = {0,45,13,12,16,9,5};//下标从1开始
  28. BinaryTree<int> t = HuffmanTree(f,N);
  29. cout<<"各字符出现的对应频率分别为:"<<endl;
  30. for(int i=1; i<=N; i++)
  31. {
  32. cout<<c[i]<<":"<<f[i]<<" ";
  33. }
  34. cout<<endl;
  35. cout<<"生成二叉树的前序遍历结果为:"<<endl;
  36. t.Pre_Order();
  37. cout<<endl;
  38. cout<<"生成二叉树的中序遍历结果为:"<<endl;
  39. t.In_Order();
  40. cout<<endl;
  41. t.DestroyTree();
  42. return 0;
  43. }
  44. template<class Type>
  45. BinaryTree<int> HuffmanTree(Type f[],int n)
  46. {
  47. //生成单节点树
  48. Huffman<Type> *w = new Huffman<Type>[n+1];
  49. BinaryTree<int> z,zero;
  50. for(int i=1; i<=n; i++)
  51. {
  52. z.MakeTree(i,zero,zero);
  53. w[i].weight = f[i];
  54. w[i].tree = z;
  55. }
  56. //建优先队列
  57. MinHeap<Huffman<Type>> Q(n);
  58. for(int i=1; i<=n; i++) Q.Insert(w[i]);
  59. //反复合并最小频率树
  60. Huffman<Type> x,y;
  61. for(int i=1; i<n; i++)
  62. {
  63. x = Q.RemoveMin();
  64. y = Q.RemoveMin();
  65. z.MakeTree(0,x.tree,y.tree);
  66. x.weight += y.weight;
  67. x.tree = z;
  68. Q.Insert(x);
  69. }
  70. x = Q.RemoveMin();
  71. delete[] w;
  72. return x.tree;
  73. }

MinHeap.h 最小堆实现

  1. #include<iostream>
  2. using namespace std;
  3. template<class T>
  4. class MinHeap
  5. {
  6. private:
  7. T *heap; //元素数组,0号位置也储存元素
  8. int CurrentSize; //目前元素个数
  9. int MaxSize; //可容纳的最多元素个数
  10. void FilterDown(const int start,const int end); //自上往下调整,使关键字小的节点在上
  11. void FilterUp(int start); //自下往上调整
  12. public:
  13. MinHeap(int n=1000);
  14. ~MinHeap();
  15. bool Insert(const T &x); //插入元素
  16. T RemoveMin(); //删除最小元素
  17. T GetMin(); //取最小元素
  18. bool IsEmpty() const;
  19. bool IsFull() const;
  20. void Clear();
  21. };
  22. template<class T>
  23. MinHeap<T>::MinHeap(int n)
  24. {
  25. MaxSize=n;
  26. heap=new T[MaxSize];
  27. CurrentSize=0;
  28. }
  29. template<class T>
  30. MinHeap<T>::~MinHeap()
  31. {
  32. delete []heap;
  33. }
  34. template<class T>
  35. void MinHeap<T>::FilterUp(int start) //自下往上调整
  36. {
  37. int j=start,i=(j-1)/2; //i指向j的双亲节点
  38. T temp=heap[j];
  39. while(j>0)
  40. {
  41. if(heap[i]<=temp)
  42. break;
  43. else
  44. {
  45. heap[j]=heap[i];
  46. j=i;
  47. i=(i-1)/2;
  48. }
  49. }
  50. heap[j]=temp;
  51. }
  52. template<class T>
  53. void MinHeap<T>::FilterDown(const int start,const int end) //自上往下调整,使关键字小的节点在上
  54. {
  55. int i=start,j=2*i+1;
  56. T temp=heap[i];
  57. while(j<=end)
  58. {
  59. if( (j<end) && (heap[j]>heap[j+1]) )
  60. j++;
  61. if(temp<=heap[j])
  62. break;
  63. else
  64. {
  65. heap[i]=heap[j];
  66. i=j;
  67. j=2*j+1;
  68. }
  69. }
  70. heap[i]=temp;
  71. }
  72. template<class T>
  73. bool MinHeap<T>::Insert(const T &x)
  74. {
  75. if(CurrentSize==MaxSize)
  76. return false;
  77. heap[CurrentSize]=x;
  78. FilterUp(CurrentSize);
  79. CurrentSize++;
  80. return true;
  81. }
  82. template<class T>
  83. T MinHeap<T>::RemoveMin( )
  84. {
  85. T x=heap[0];
  86. heap[0]=heap[CurrentSize-1];
  87. CurrentSize--;
  88. FilterDown(0,CurrentSize-1); //调整新的根节点
  89. return x;
  90. }
  91. template<class T>
  92. T MinHeap<T>::GetMin()
  93. {
  94. return heap[0];
  95. }
  96. template<class T>
  97. bool MinHeap<T>::IsEmpty() const
  98. {
  99. return CurrentSize==0;
  100. }
  101. template<class T>
  102. bool MinHeap<T>::IsFull() const
  103. {
  104. return CurrentSize==MaxSize;
  105. }
  106. template<class T>
  107. void MinHeap<T>::Clear()
  108. {
  109. CurrentSize=0;
  110. }

BinaryTree.h 二叉树实现

  1. #include<iostream>
  2. using namespace std;
  3. template<class T>
  4. struct BTNode
  5. {
  6. T data;
  7. BTNode<T> *lChild,*rChild;
  8. BTNode()
  9. {
  10. lChild=rChild=NULL;
  11. }
  12. BTNode(const T &val,BTNode<T> *Childl=NULL,BTNode<T> *Childr=NULL)
  13. {
  14. data=val;
  15. lChild=Childl;
  16. rChild=Childr;
  17. }
  18. BTNode<T>* CopyTree()
  19. {
  20. BTNode<T> *nl,*nr,*nn;
  21. if(&data==NULL)
  22. return NULL;
  23. nl=lChild->CopyTree();
  24. nr=rChild->CopyTree();
  25. nn=new BTNode<T>(data,nl,nr);
  26. return nn;
  27. }
  28. };
  29. template<class T>
  30. class BinaryTree
  31. {
  32. public:
  33. BTNode<T> *root;
  34. BinaryTree();
  35. ~BinaryTree();
  36. void Pre_Order();
  37. void In_Order();
  38. void Post_Order();
  39. int TreeHeight()const;
  40. int TreeNodeCount()const;
  41. void DestroyTree();
  42. void MakeTree(T pData,BinaryTree<T> leftTree,BinaryTree<T> rightTree);
  43. void Change(BTNode<T> *r);
  44. private:
  45. void Destroy(BTNode<T> *&r);
  46. void PreOrder(BTNode<T> *r);
  47. void InOrder(BTNode<T> *r);
  48. void PostOrder(BTNode<T> *r);
  49. int Height(const BTNode<T> *r)const;
  50. int NodeCount(const BTNode<T> *r)const;
  51. };
  52. template<class T>
  53. BinaryTree<T>::BinaryTree()
  54. {
  55. root=NULL;
  56. }
  57. template<class T>
  58. BinaryTree<T>::~BinaryTree()
  59. {
  60. }
  61. template<class T>
  62. void BinaryTree<T>::Pre_Order()
  63. {
  64. PreOrder(root);
  65. }
  66. template<class T>
  67. void BinaryTree<T>::In_Order()
  68. {
  69. InOrder(root);
  70. }
  71. template<class T>
  72. void BinaryTree<T>::Post_Order()
  73. {
  74. PostOrder(root);
  75. }
  76. template<class T>
  77. int BinaryTree<T>::TreeHeight()const
  78. {
  79. return Height(root);
  80. }
  81. template<class T>
  82. int BinaryTree<T>::TreeNodeCount()const
  83. {
  84. return NodeCount(root);
  85. }
  86. template<class T>
  87. void BinaryTree<T>::DestroyTree()
  88. {
  89. Destroy(root);
  90. }
  91. template<class T>
  92. void BinaryTree<T>::PreOrder(BTNode<T> *r)
  93. {
  94. if(r!=NULL)
  95. {
  96. cout<<r->data<<' ';
  97. PreOrder(r->lChild);
  98. PreOrder(r->rChild);
  99. }
  100. }
  101. template<class T>
  102. void BinaryTree<T>::InOrder(BTNode<T> *r)
  103. {
  104. if(r!=NULL)
  105. {
  106. InOrder(r->lChild);
  107. cout<<r->data<<' ';
  108. InOrder(r->rChild);
  109. }
  110. }
  111. template<class T>
  112. void BinaryTree<T>::PostOrder(BTNode<T> *r)
  113. {
  114. if(r!=NULL)
  115. {
  116. PostOrder(r->lChild);
  117. PostOrder(r->rChild);
  118. cout<<r->data<<' ';
  119. }
  120. }
  121. template<class T>
  122. int BinaryTree<T>::NodeCount(const BTNode<T> *r)const
  123. {
  124. if(r==NULL)
  125. return 0;
  126. else
  127. return 1+NodeCount(r->lChild)+NodeCount(r->rChild);
  128. }
  129. template<class T>
  130. int BinaryTree<T>::Height(const BTNode<T> *r)const
  131. {
  132. if(r==NULL)
  133. return 0;
  134. else
  135. {
  136. int lh,rh;
  137. lh=Height(r->lChild);
  138. rh=Height(r->rChild);
  139. return 1+(lh>rh?lh:rh);
  140. }
  141. }
  142. template<class T>
  143. void BinaryTree<T>::Destroy(BTNode<T> *&r)
  144. {
  145. if(r!=NULL)
  146. {
  147. Destroy(r->lChild);
  148. Destroy(r->rChild);
  149. delete r;
  150. r=NULL;
  151. }
  152. }
  153. template<class T>
  154. void BinaryTree<T>::Change(BTNode<T> *r)//将二叉树bt所有结点的左右子树交换
  155. {
  156. BTNode<T> *p;
  157. if(r){
  158. p=r->lChild;
  159. r->lChild=r->rChild;
  160. r->rChild=p; //左右子女交换
  161. Change(r->lChild); //交换左子树上所有结点的左右子树
  162. Change(r->rChild); //交换右子树上所有结点的左右子树
  163. }
  164. }
  165. template<class T>
  166. void BinaryTree<T>::MakeTree(T pData,BinaryTree<T> leftTree,BinaryTree<T> rightTree)
  167. {
  168. root = new BTNode<T>();
  169. root->data = pData;
  170. root->lChild = leftTree.root;
  171. root->rChild = rightTree.root;
  172. }

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

闽ICP备14008679号