贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题他能产生整体最优解或者是整体最优解的近似解。
贪心算法的基本要素
对于一个具体的问题,怎么知道是否可用贪心算法解此问题,以及能否得到问题的最优解呢?这个问题很难给予肯定的回答。
但是,从许多可以用贪心算法求解的问题中看到这类问题一般具有2个重要的性质:贪心选择性质和最优子结构性质。
1、贪心选择性质
所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这是贪心算法可行的第一个基本要素,也是贪心算法与动态规划算法的主要区别。
动态规划算法通常以自底向上的方式解各子问题,而贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。
对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解。
2、最优子结构性质
当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。问题的最优子结构性质是该问题可用动态规划算法或贪心算法求解的关键特征。
哈夫曼编码是广泛地用于数据文件压缩的十分有效的编码方法。其压缩率通常在20%~90%之间。哈夫曼编码算法用字符在文件中出现的频率表来建立一个用0,1串表示各字符的最优表示方式。
给出现频率高的字符较短的编码,出现频率较低的字符以较长的编码,可以大大缩短总码长。
a | b | c | d | e | f | |
频率(千次) | 45 | 13 | 12 | 16 | 9 | 5 |
定长码 | 000 | 001 | 010 | 011 | 100 | 101 |
变长码 | 0 | 101 | 100 | 111 | 1101 | 1100 |
代码如下:
#include<iostream> using namespace std; typedef struct HuffmanTree { char value; int rate; HuffmanTree *lchild; HuffmanTree *rchild; }*TreePointer; //维护当前树为小顶堆 void Min_Heapify(HuffmanTree *treeArray,int i,int length) { int min,temp; int left = i * 2; int right = i * 2 + 1; if((left <= length)&&(treeArray[left].rate < treeArray[i].rate)) min = left; else min = i; if((right <= length)&&(treeArray[right].rate < treeArray[min].rate)) min = right; if(min != i) { HuffmanTree temptree; temptree.rate = treeArray[i].rate; temptree.value = treeArray[i].value; temptree.lchild = treeArray[i].lchild; temptree.rchild = treeArray[i].rchild; treeArray[i].rate = treeArray[min].rate; treeArray[i].value = treeArray[min].value; treeArray[i].lchild = treeArray[min].lchild; treeArray[i].rchild = treeArray[min].rchild; treeArray[min].rate = temptree.rate; treeArray[min].value = temptree.value; treeArray[min].lchild = temptree.lchild; treeArray[min].rchild = temptree.rchild; Min_Heapify(treeArray,min,length); } } void Build_Min_Heap(HuffmanTree *treeArray,int length) { for(int i = length / 2; i >= 1; i--) Min_Heapify(treeArray,i,length); } //只调整尾部新进元素 void AdjustmentTail_Huffman_Heap(HuffmanTree *treeArray,int location) { HuffmanTree temptree; if(((location / 2 )!= 0)&&(treeArray[location].rate < treeArray[location / 2].rate)) { temptree.rate = treeArray[location / 2].rate; temptree.value = treeArray[location / 2].value; temptree.lchild = treeArray[location / 2].lchild; temptree.rchild = treeArray[location / 2].rchild; treeArray[location / 2].rate = treeArray[location].rate; treeArray[location / 2].value = treeArray[location].value; treeArray[location / 2].lchild = treeArray[location].lchild; treeArray[location / 2].rchild = treeArray[location].rchild; treeArray[location].rate = temptree.rate; treeArray[location].value = temptree.value; treeArray[location].lchild = temptree.lchild; treeArray[location].rchild = temptree.rchild; AdjustmentTail_Huffman_Heap(treeArray,location / 2); } } HuffmanTree* Extract_Min(HuffmanTree *treeArray,int &length) { treeArray[0].rate = treeArray[1].rate; treeArray[0].value = treeArray[1].value; treeArray[0].lchild = treeArray[1].lchild; treeArray[0].rchild = treeArray[1].rchild; treeArray[1].rate = treeArray[length].rate; treeArray[1].value = treeArray[length].value; treeArray[1].lchild = treeArray[length].lchild; treeArray[1].rchild = treeArray[length].rchild; Min_Heapify(treeArray,1,length - 1); length--; return &treeArray[0]; } HuffmanTree* Build_Huffman_Tree(HuffmanTree *treeArray,int length) { HuffmanTree *left; HuffmanTree *right; HuffmanTree *root; HuffmanTree *temp; int n = length; for(int i = 1; i<= n-1; i++) { left = (HuffmanTree*)malloc(sizeof(HuffmanTree)); right = (HuffmanTree*)malloc(sizeof(HuffmanTree)); temp = Extract_Min(treeArray,length); left->rate = temp->rate; left->value = temp->value; left->lchild = temp->lchild; left->rchild = temp->rchild; temp = Extract_Min(treeArray,length); right->rate = temp->rate; right->value = temp->value; right->lchild = temp->lchild; right->rchild = temp->rchild; length++; treeArray[length].lchild = left; treeArray[length].rchild = right; treeArray[length].rate = left->rate + right->rate; treeArray[length].value = 0; AdjustmentTail_Huffman_Heap(treeArray,length); } root = (HuffmanTree*)malloc(sizeof(HuffmanTree)); root->rate = treeArray[1].rate; root->value = treeArray[1].value; root->lchild = treeArray[1].lchild; root->rchild = treeArray[1].rchild; return root; } void Print_Huffman_Code(HuffmanTree *root,int *code,int length) { if(root != NULL) { if(root->value != 0) { cout<<root->value<<" "; for(int i = 0;i < length;i++) { cout<<code[i]<<" "; } cout<<endl; } code[length++] = 0; Print_Huffman_Code(root->lchild,code,length); length--; code[length++] = 1; Print_Huffman_Code(root->rchild,code,length); length--; } } int main() { HuffmanTree treeArray[7]; treeArray[1].value = 'e'; treeArray[1].rate = 9; treeArray[1].lchild = NULL; treeArray[1].rchild = NULL; treeArray[2].value = 'c'; treeArray[2].rate = 12; treeArray[2].lchild = NULL; treeArray[2].rchild = NULL; treeArray[3].value = 'b'; treeArray[3].rate = 13; treeArray[3].lchild = NULL; treeArray[3].rchild = NULL; treeArray[4].value = 'f'; treeArray[4].rate = 5; treeArray[4].lchild = NULL; treeArray[4].rchild = NULL; treeArray[5].value = 'd'; treeArray[5].rate = 16; treeArray[5].lchild = NULL; treeArray[5].rchild = NULL; treeArray[6].value = 'a'; treeArray[6].rate = 45; treeArray[6].lchild = NULL; treeArray[6].rchild = NULL; Build_Min_Heap(treeArray,6); HuffmanTree *root = Build_Huffman_Tree(treeArray,6); int code[6]; Print_Huffman_Code(root,code,0); return 0; }