1、0023算法笔记贪心算法哈夫曼编码问题docx0023 算法笔记【贪心算法】哈夫曼编码问题1 、问题描述哈夫曼编码是广泛地用于数据文件压缩的十分有效的编码方法。 其压缩率通常在 20%90%之间。哈夫曼编码算法用字符在文件中出 现的频率表来建立一个用 0,1串表示各字符的最优表示方式。一个包 含 100,000 个字符的文件,各字符出现频率不同,如下表所示。有多种方式表示文件中的信息,若用 0,1 码表示字符的方法,即每 个字符用唯一的一个 0,1 串表示。若采用定长编码表示,则需要 3位表 示一个字符,整个文件编码需要300,000 位;若采用变长编码表示,给 频率高的字符较短的编码;频率低
2、的字符较长的编码,达到整体编码减少的目的,则整 个文件编码需要(451+133+123+163+94+54) 1000=224,000 位,由此可见,变长码比定长码方案好,总码长减小 约 25% 。前缀码:对每一个字符规定一个 0,1 串作为其代码,并要求任一字 符的代码都不是其他字符代码的前缀。这种编码称为前缀码。编码的 前缀性质可以使译码方法非常简单;例如 001011101 可以唯一的分解 为 0,0,101,1101,因而其译码为 aabe。译码过程需要方便的取出编码的前缀,因此需要表示前缀码的合 适的数据结构。为此,可以用二叉树作为前缀码的数据结构:树叶表 示给定字符;从树根到树叶的
3、路径当作该字符的前缀码;代码中每一 位的 0 或 1 分别作为指示某节点到左儿子或右儿子的“路标”。从上图可以看出,表示最优前缀码的二叉树总是一棵完全二叉 树,即树中任意节点都有 2 个儿子。图a 表示定长编码方案不是最优 的,其编码的二叉树不是一棵完全二叉树。在一般情况下,若 C 是编 码字符集,表示其最优前缀码的二叉树中恰有|C|个叶子。每个叶子对 应于字符集中的一个字符,该二叉树有|C|-1 个内部节点。给定编码字符集 C 及频率分布 f,即 C 中任一字符 c 以频率 f(c) 在 数据文件中出现。C 的一个前缀码编码方案对应于一棵二叉树 T。字 符 c 在树 T 中的深度记为 dT(
4、c) 。 dT(c) 也是字符 c 的前缀码长。则平均码长定义为: 使平均码长达到最小的前缀码编码方案称为C 的最优前缀码。2 、构造哈弗曼编码哈夫曼提出构造最优前缀码的贪心算法,由此产生的编码方案称 为哈夫曼编码。其构造步骤如下:(1)哈夫曼算法以自底向上的方式构造表示最优前缀码的二叉树 T。(2)算法以|C|个叶结点开始,执行|C|1 次的“合并”运算后产生最 终所要求的树 T。(3)假设编码字符集中每一字符 c 的频率是 f(c)。以 f 为键值的优先 队列 Q 用在贪心选择时有效地确定算法当前要合并的 2棵具有最小频 率的树。一旦 2 棵具有最小频率的树合并后,产生一棵新的树,其频 率
5、为合并的 2 棵树的频率之和,并将新树插入优先队列 Q。经过 n1 次的合并后,优先队列中只剩下一棵树,即所要求的树 T。构造过程如图所示:具体代码实现如下:(1)4d4.cpp ,程序主文件cpp view plain copy1.2.3.4.5.6.7.8.9./4d4 贪心算法 哈夫曼算法 #include stdafx.h #include BinaryTree.h #include MinHeap.h #include using namespace std;const int N = 6;10. template class Huffman;11.12. template13. B
6、inaryTree HuffmanTree(Type f,int n);14.15. template16. class Huffman 17. 18. friend BinaryTree HuffmanTree(Type,int);19. public:21.20. operator Type() const22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.return weigh
7、t;/private:BinaryTree tree;Type weight;int main()char c = 0,a,b,c,d,e,f; int f = 0,45,13,12,16,9,5;/下标从 1 开始 BinaryTree t = HuffmanTree(f,N);cout各字符出现的对应频率分别为:endl; for(int i=1; i=N; i+)coutci:fi ;coutendl;cout生成二叉树的前序遍历结果为:endl; t.Pre_Order();coutendl;cout生成二叉树的中序遍历结果为:endl; t.In_Order();coutendl;t
8、.DestroyTree();return 0;templateBinaryTree HuffmanTree(Type f,int n)/生成单节点树Huffman *w = new Huffmann+1;BinaryTree z,zero;for(int i=1; i=n; i+)z.MakeTree(i,zero,zero); wi.weight = fi;wi.tree = z;66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89. *Childr=NULL)/建优先队列MinHeapHuffman
9、 Q(n); for(int i=1; i=n; i+) Q.Insert(wi);/反复合并最小频率树Huffman x,y;for(int i=1; in; i+)x = Q.RemoveMin();y = Q.RemoveMin();z.MakeTree(0,x.tree,y.tree);x.weight += y.weight;x.tree = z;Q.Insert(x);x = Q.RemoveMin();delete w;return x.tree;(2)BinaryTree.h 二叉树实现cpp view plain copy1. #include2. using namespa
10、ce std;3.4. template5. struct BTNode6.7.T data;8.BTNode *lChild,*rChild;9.10.BTNode()11.12.lChild=rChild=NULL;13.14.15. BTNode(const T &val,BTNode *Childl=NULL,BTNode16. 17.data=val;18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.5
11、7.58.59.60.lChild=Childl;rChild=Childr;BTNode* CopyTree()BTNode *nl,*nr,*nn;if(&data=NULL)return NULL;nl=lChild-CopyTree();nr=rChild-CopyTree();nn=new BTNode(data,nl,nr);return nn;templateclass BinaryTreepublic:BTNode *root;BinaryTree();BinaryTree();void Pre_Order();void In_Order();void Post_Order()
12、;int TreeHeight()const;int TreeNodeCount()const;void DestroyTree();void MakeTree(T pData,BinaryTree leftTree,BinaryTree rightTree);void Change(BTNode *r);private:void Destroy(BTNode *&r);void PreOrder(BTNode *r);void InOrder(BTNode *r);61. void PostOrder(BTNode *r);62.63. int Height(const BTNode *r)
13、const;64. int NodeCount(const BTNode *r)const;65. ;66.67. template68.BinaryTree:BinaryTree()69.70.root=NULL;71.72.73. template74. BinaryTree:BinaryTree()75. 76.77. 78.79. template80.void BinaryTree:Pre_Order()81.82.PreOrder(root);83.84.85. template86.void BinaryTree:In_Order()87.88.InOrder(root);89.
14、90.91. template92.void BinaryTree:Post_Order()93.94.PostOrder(root);95.96.97. template98.int BinaryTree:TreeHeight()const99.100.return Height(root);101.102.103. template104. int BinaryTree:TreeNodeCount()const105.106.107.108.109.110.111.112.113.114.115.116.117.118.119.120.121.122.123.124.125.126.127
15、.128.129.130.131.132.133.134.135.136.137.138.139.140.141.142.143.144.145.146.147.148.return NodeCount(root);templatevoid BinaryTree:DestroyTree()Destroy(root);templatevoid BinaryTree:PreOrder(BTNode *r)if(r!=NULL)coutdatalChild); PreOrder(r-rChild);templatevoid BinaryTree:InOrder(BTNode *r)if(r!=NUL
16、L)InOrder(r-lChild); coutdatarChild); templatevoid BinaryTree:PostOrder(BTNode *r)if(r!=NULL)PostOrder(r-lChild);PostOrder(r-rChild); coutdata ;template149.150.151.152.153.154.155.156.157.158.159.160.161.162.163.164.165.166.167.168.169.170.171.172.173.174.175.176.177.178.179.180.181.182.183.184.185.
17、186.187.188.189.190.191.192.int BinaryTree:NodeCount(const BTNode *r)constif(r=NULL)return 0;elsereturn 1+NodeCount(r-lChild)+NodeCount(r-rChild);templateint BinaryTree:Height(const BTNode *r)constif(r=NULL)return 0;elseint lh,rh;lh=Height(r-lChild);rh=Height(r-rChild);return 1+(lhrh?lh:rh);template
18、void BinaryTree:Destroy(BTNode *&r)if(r!=NULL)Destroy(r-lChild);Destroy(r-rChild);delete r;r=NULL;templatevoid BinaryTree:Change(BTNode *r)/将二叉树 bt 所有结点的左右子树交换BTNode *p;if(r)p=r-lChild; r-lChild=r-rChild;r-rChild=p; /左右子女交换Change(r-lChild); /交换左子树上所有结点的左右子树Change(r-rChild); /交换右子树上所有结点的左右子树194. 195.
19、196. template197. void BinaryTree:MakeTree(T pData,BinaryTree leftTree,BinaryTree r ightTree)198.199.root = new BTNode();200.root-data = pData;201.root-lChild = leftTree.root;202.root-rChild = rightTree.root203.(3)MinHeap.h 最小堆实现cpp view plain copy1. #include 2. using namespace std;3. template4. cla
20、ss MinHeap5. 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); /插入元素
21、18.19. T RemoveMin(); /删除最小元素20. T GetMin(); /取最小元素21.22.23.24.25. ;26.bool IsEmpty() const; bool IsFull() const; void Clear();27. template28. MinHeap:MinHeap(int n)29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.MaxSiz
22、e=n;heap=new TMaxSize;CurrentSize=0;templateMinHeap:MinHeap()delete heap;templatevoid MinHeap:FilterUp(int start) /自下往上调整int j=start,i=(j-1)/2; /i 指向 j 的双亲节点T temp=heapj;while(j0)if(heapi=temp)break;elseheapj=heapi;j=i;i=(i-1)/2; heapj=temp;templatevoid MinHeap:FilterDown(const int start,const int e
23、nd) /自上往下调整,使 关键字小的节点在上int i=start,j=2*i+1;T temp=heapi;while(j=end)if( (jheapj+1) ) j+;if(temp=heapj) break;77.78.79.heapi=temp;80.81.82. template83.bool MinHeap:Insert(const T &x)84.85.if(CurrentSize=MaxSize)86. return false;87.88. heapCurrentSize=x;89. FilterUp(CurrentSize);90.91. CurrentSize+;92
24、. return true;93. 94.95. template96.T MinHeap:RemoveMin( )97.98.T x=heap0;99.heap0=heapCurrentSize-1;100.101. CurrentSize-;102. FilterDown(0,CurrentSize-1); /调整新的根节点103.104. return x;105. 106.107. template108. T MinHeap:GetMin()109. 110. return heap0;111. 112.113. template114. bool MinHeap:IsEmpty()
25、 const115. 116.return CurrentSize=0;117.118.119.template120.bool MinHeap:IsFull() const121.122.return CurrentSize=MaxSize;123.124.125.template126.void MinHeap: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 的
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1