0023算法笔记——【贪心算法】哈夫曼编码问题.docx
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 贪心算法 0023 算法 笔记 贪心 哈夫曼 编码 问题
- 资源描述:
-
0023算法笔记——【贪心算法】哈夫曼编码问题 1、问题描述 哈夫曼编码是广泛地用于数据文件压缩的十分有效的编码方法。其压缩率通常在20%~90%之间。哈夫曼编码算法用字符在文件中出现的频率表来建立一个用0,1串表示各字符的最优表示方式。一个包含100,000个字符的文件,各字符出现频率不同,如下表所示。 有多种方式表示文件中的信息,若用0,1码表示字符的方法,即每个字符用唯一的一个0,1串表示。若采用定长编码表示,则需要3位表示一个字符,整个文件编码需要300,000位;若采用变长编码表示,给频率高的字符较短的编码;频率低的字符较长的编码,达到整体编码减少的目的,则整个文件编码需要(45×1+13×3+12×3+16×3+9×4+5×4)×1000=224,000位,由此可见,变长码比定长码方案好,总码长减小约25%。 前缀码:对每一个字符规定一个0,1串作为其代码,并要求任一字符的代码都不是其他字符代码的前缀。这种编码称为前缀码。编码的前缀性质可以使译码方法非常简单;例如001011101可以唯一的分解为0,0,101,1101,因而其译码为aabe。 译码过程需要方便的取出编码的前缀,因此需要表示前缀码的合适的数据结构。为此,可以用二叉树作为前缀码的数据结构:树叶表示给定字符;从树根到树叶的路径当作该字符的前缀码;代码中每一位的0或1分别作为指示某节点到左儿子或右儿子的“路标”。 从上图可以看出,表示最优前缀码的二叉树总是一棵完全二叉树,即树中任意节点都有2个儿子。图a表示定长编码方案不是最优的,其编码的二叉树不是一棵完全二叉树。在一般情况下,若C是编码字符集,表示其最优前缀码的二叉树中恰有|C|个叶子。每个叶子对应于字符集中的一个字符,该二叉树有|C|-1个内部节点。 给定编码字符集C及频率分布f,即C中任一字符c以频率f(c)在数据文件中出现。C的一个前缀码编码方案对应于一棵二叉树T。字符c在树T中的深度记为dT(c)。dT(c)也是字符c的前缀码长。则平均码长定义为:使平均码长达到最小的前缀码编码方案称为C的最优前缀码。 2、构造哈弗曼编码 哈夫曼提出构造最优前缀码的贪心算法,由此产生的编码方案称为哈夫曼编码。其构造步骤如下: (1)哈夫曼算法以自底向上的方式构造表示最优前缀码的二叉树T。 (2)算法以|C|个叶结点开始,执行|C|-1次的“合并”运算后产生最终所要求的树T。 (3)假设编码字符集中每一字符c的频率是f(c)。以f为键值的优先队列Q用在贪心选择时有效地确定算法当前要合并的2棵具有最小频率的树。一旦2棵具有最小频率的树合并后,产生一棵新的树,其频率为合并的2棵树的频率之和,并将新树插入优先队列Q。经过n-1次的合并后,优先队列中只剩下一棵树,即所要求的树T。 构造过程如图所示: 具体代码实现如下: (1)4d4.cpp,程序主文件 [cpp] view plain copy 1. //4d4 贪心算法 哈夫曼算法 2. #include "stdafx.h" 3. #include "BinaryTree.h" 4. #include "MinHeap.h" 5. #include <iostream> 6. using namespace std; 7. 8. const int N = 6; 9. 10. template<class Type> class Huffman; 11. 12. template<class Type> 13. BinaryTree<int> HuffmanTree(Type f[],int n); 14. 15. template<class Type> 16. class Huffman 17. { 18. friend BinaryTree<int> HuffmanTree(Type[],int); 19. public: 20. operator Type() const 21. { 22. return weight; 23. } 24. //private: 25. BinaryTree<int> tree; 26. Type weight; 27. }; 28. 29. int main() 30. { 31. char c[] = {'0','a','b','c','d','e','f'}; 32. int f[] = {0,45,13,12,16,9,5};//下标从1开始 33. BinaryTree<int> t = HuffmanTree(f,N); 34. 35. cout<<"各字符出现的对应频率分别为:"<<endl; 36. for(int i=1; i<=N; i++) 37. { 38. cout<<c[i]<<":"<<f[i]<<" "; 39. } 40. cout<<endl; 41. 42. cout<<"生成二叉树的前序遍历结果为:"<<endl; 43. t.Pre_Order(); 44. cout<<endl; 45. 46. cout<<"生成二叉树的中序遍历结果为:"<<endl; 47. t.In_Order(); 48. cout<<endl; 49. 50. t.DestroyTree(); 51. return 0; 52. } 53. 54. template<class Type> 55. BinaryTree<int> HuffmanTree(Type f[],int n) 56. { 57. //生成单节点树 58. Huffman<Type> *w = new Huffman<Type>[n+1]; 59. BinaryTree<int> z,zero; 60. 61. for(int i=1; i<=n; i++) 62. { 63. z.MakeTree(i,zero,zero); 64. w[i].weight = f[i]; 65. w[i].tree = z; 66. } 67. 68. //建优先队列 69. MinHeap<Huffman<Type>> Q(n); 70. for(int i=1; i<=n; i++) Q.Insert(w[i]); 71. 72. //反复合并最小频率树 73. Huffman<Type> x,y; 74. for(int i=1; i<n; i++) 75. { 76. x = Q.RemoveMin(); 77. y = Q.RemoveMin(); 78. z.MakeTree(0,x.tree,y.tree); 79. x.weight += y.weight; 80. x.tree = z; 81. Q.Insert(x); 82. } 83. 84. x = Q.RemoveMin(); 85. 86. delete[] w; 87. 88. return x.tree; 89. } (2)BinaryTree.h 二叉树实现 [cpp] view plain copy 1. #include<iostream> 2. using namespace std; 3. 4. template<class T> 5. struct BTNode 6. { 7. T data; 8. BTNode<T> *lChild,*rChild; 9. 10. BTNode() 11. { 12. lChild=rChild=NULL; 13. } 14. 15. BTNode(const T &val,BTNode<T> *Childl=NULL,BTNode<T> *Childr=NULL) 16. { 17. data=val; 18. lChild=Childl; 19. rChild=Childr; 20. } 21. 22. BTNode<T>* CopyTree() 23. { 24. BTNode<T> *nl,*nr,*nn; 25. 26. if(&data==NULL) 27. return NULL; 28. 29. nl=lChild->CopyTree(); 30. nr=rChild->CopyTree(); 31. 32. nn=new BTNode<T>(data,nl,nr); 33. return nn; 34. } 35. }; 36. 37. 38. template<class T> 39. class BinaryTree 40. { 41. public: 42. BTNode<T> *root; 43. BinaryTree(); 44. ~BinaryTree(); 45. 46. void Pre_Order(); 47. void In_Order(); 48. void Post_Order(); 49. 50. int TreeHeight()const; 51. int TreeNodeCount()const; 52. 53. void DestroyTree(); 54. void MakeTree(T pData,BinaryTree<T> leftTree,BinaryTree<T> rightTree); 55. void Change(BTNode<T> *r); 56. 57. private: 58. void Destroy(BTNode<T> *&r); 59. void PreOrder(BTNode<T> *r); 60. void InOrder(BTNode<T> *r); 61. void PostOrder(BTNode<T> *r); 62. 63. int Height(const BTNode<T> *r)const; 64. int NodeCount(const BTNode<T> *r)const; 65. }; 66. 67. template<class T> 68. BinaryTree<T>::BinaryTree() 69. { 70. root=NULL; 71. } 72. 73. template<class T> 74. BinaryTree<T>::~BinaryTree() 75. { 76. 77. } 78. 79. template<class T> 80. void BinaryTree<T>::Pre_Order() 81. { 82. PreOrder(root); 83. } 84. 85. template<class T> 86. void BinaryTree<T>::In_Order() 87. { 88. InOrder(root); 89. } 90. 91. template<class T> 92. void BinaryTree<T>::Post_Order() 93. { 94. PostOrder(root); 95. } 96. 97. template<class T> 98. int BinaryTree<T>::TreeHeight()const 99. { 100. return Height(root); 101. } 102. 103. template<class T> 104. int BinaryTree<T>::TreeNodeCount()const 105. { 106. return NodeCount(root); 107. } 108. 109. template<class T> 110. void BinaryTree<T>::DestroyTree() 111. { 112. Destroy(root); 113. } 114. 115. template<class T> 116. void BinaryTree<T>::PreOrder(BTNode<T> *r) 117. { 118. if(r!=NULL) 119. { 120. cout<<r->data<<' '; 121. PreOrder(r->lChild); 122. PreOrder(r->rChild); 123. } 124. } 125. 126. template<class T> 127. void BinaryTree<T>::InOrder(BTNode<T> *r) 128. { 129. if(r!=NULL) 130. { 131. InOrder(r->lChild); 132. cout<<r->data<<' '; 133. InOrder(r->rChild); 134. } 135. } 136. 137. template<class T> 138. void BinaryTree<T>::PostOrder(BTNode<T> *r) 139. { 140. if(r!=NULL) 141. { 142. PostOrder(r->lChild); 143. PostOrder(r->rChild); 144. cout<<r->data<<' '; 145. } 146. } 147. 148. template<class T> 149. int BinaryTree<T>::NodeCount(const BTNode<T> *r)const 150. { 151. if(r==NULL) 152. return 0; 153. else 154. return 1+NodeCount(r->lChild)+NodeCount(r->rChild); 155. } 156. 157. template<class T> 158. int BinaryTree<T>::Height(const BTNode<T> *r)const 159. { 160. if(r==NULL) 161. return 0; 162. else 163. { 164. int lh,rh; 165. lh=Height(r->lChild); 166. rh=Height(r->rChild); 167. return 1+(lh>rh?lh:rh); 168. } 169. } 170. 171. template<class T> 172. void BinaryTree<T>::Destroy(BTNode<T> *&r) 173. { 174. if(r!=NULL) 175. { 176. Destroy(r->lChild); 177. Destroy(r->rChild); 178. delete r; 179. r=NULL; 180. } 181. } 182. 183. template<class T> 184. void BinaryTree<T>::Change(BTNode<T> *r)//将二叉树bt所有结点的左右子树交换 185. { 186. BTNode<T> *p; 187. if(r){ 188. p=r->lChild; 189. r->lChild=r->rChild; 190. r->rChild=p; //左右子女交换 191. Change(r->lChild); //交换左子树上所有结点的左右子树 192. Change(r->rChild); //交换右子树上所有结点的左右子树 193. } 194. } 195. 196. template<class T> 197. void BinaryTree<T>::MakeTree(T pData,BinaryTree<T> leftTree,BinaryTree<T> rightTree) 198. { 199. root = new BTNode<T>(); 200. root->data = pData; 201. root->lChild = leftTree.root; 202. root->rChild = rightTree.root; 203. } (3)MinHeap.h 最小堆实现 [cpp] view plain copy 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. 11. void FilterDown(const int start,const int end); //自上往下调整,使关键字小的节点在上 12. void FilterUp(int start); //自下往上调整 13. 14. public: 15. MinHeap(int n=1000); 16. ~MinHeap(); 17. bool Insert(const T &x); //插入元素 18. 19. T RemoveMin(); //删除最小元素 20. T GetMin(); //取最小元素 21. 22. bool IsEmpty() const; 23. bool IsFull() const; 24. void Clear(); 25. }; 26. 27. template<class T> 28. MinHeap<T>::MinHeap(int n) 29. { 30. MaxSize=n; 31. heap=new T[MaxSize]; 32. CurrentSize=0; 33. } 34. 35. template<class T> 36. MinHeap<T>::~MinHeap() 37. { 38. delete []heap; 39. } 40. 41. template<class T> 42. void MinHeap<T>::FilterUp(int start) //自下往上调整 43. { 44. int j=start,i=(j-1)/2; //i指向j的双亲节点 45. T temp=heap[j]; 46. 47. while(j>0) 48. { 49. if(heap[i]<=temp) 50. break; 51. else 52. { 53. heap[j]=heap[i]; 54. j=i; 55. i=(i-1)/2; 56. } 57. } 58. heap[j]=temp; 59. } 60. 61. template<class T> 62. void MinHeap<T>::FilterDown(const int start,const int end) //自上往下调整,使关键字小的节点在上 63. { 64. int i=start,j=2*i+1; 65. T temp=heap[i]; 66. while(j<=end) 67. { 68. if( (j<end) && (heap[j]>heap[j+1]) ) 69. j++; 70. if(temp<=heap[j]) 71. break; 72. else 73. { 74. heap[i]=heap[j]; 75. i=j; 76. j=2*j+1; 77. } 78. } 79. heap[i]=temp; 80. } 81. 82. template<class T> 83. bool MinHeap<T>::Insert(const T &x) 84. { 85. if(CurrentSize==MaxSize) 86. return false; 87. 88. heap[CurrentSize]=x; 89. FilterUp(CurrentSize); 90. 91. CurrentSize++; 92. return true; 93. } 94. 95. template<class T> 96. T MinHeap<T>::RemoveMin( ) 97. { 98. T x=heap[0]; 99. heap[0]=heap[CurrentSize-1]; 100. 101. CurrentSize--; 102. FilterDown(0,CurrentSize-1); //调整新的根节点 103. 104. return x; 105. } 106. 107. template<class T> 108. T MinHeap<T>::GetMin() 109. { 110. return heap[0]; 111. } 112. 113. template<class T> 114. bool MinHeap<T>::IsEmpty() const 115. { 116. return CurrentSize==0; 117. } 118. 119. template<class T> 120. bool MinHeap<T>::IsFull() const 121. { 122. return CurrentSize==MaxSize; 123. } 124. 125. template<class T> 126. void MinHeap<T>::Clear() 127. { 128. CurrentSize=0; 129. } 3、贪心选择性质 二叉树T表示字符集C的一个最优前缀码,证明可以对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和T'的前缀码的平均码长之差为: 因此,T''表示的前缀码也是最优前缀码,且x,y具有相同的码长,同时,仅最优一位编码不同。 4、最优子结构性质 二叉树T表示字符集C的一个最优前缀码,x和y是树T中的两个叶子且为兄弟,z是它们的父亲。若将z当作是具有频率f(z)=f(x)+f(y)的字符,则树T’=T-{x,y}表示字符集C’=C-{x, y} ∪ { z}的一个最优前缀码。因此,有: 如果T’不是C’的最优前缀码,假定T”是C’的最优前缀码,那么有,显然T”’是比T更优的前缀码,跟前提矛盾!故T'所表示的C'的前缀码是最优的。 由贪心选择性质和最优子结构性质可以推出哈夫曼算法是正确的,即HuffmanTree产生的一棵最优前缀编码树。 程序运行结果如图:展开阅读全文
咨信网温馨提示:1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前可先查看【教您几个在下载文档中可以更好的避免被坑】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时联系平台进行协调解决,联系【微信客服】、【QQ客服】,若有其他问题请点击或扫码反馈【服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【版权申诉】”,意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:0574-28810668;投诉电话:18658249818。




0023算法笔记——【贪心算法】哈夫曼编码问题.docx



实名认证













自信AI助手
















微信客服
客服QQ
发送邮件
意见反馈



链接地址:https://www.zixin.com.cn/doc/4336868.html