实验三.哈夫曼编码的贪心算法设计
实验三-贪心算法

for(inti=0;i<s.length();i++){
buf.append(getEachCode(s.substring(i,i+1)));
}
returnbuf.toString();
}
publicString getEachCode(String name){
for(inti=0;i<buffer.length();i++){
if(name.equals(codes[i].name)){
returnhuffstring[i];
}
}
return"";
}
publicvoidgetCode(intn,String[] thecodes,String thebuffer){
importjava.util.Scanner;
classHuffmanCode{
Stringname;
doubleweight;
intlc,rc,pa;
publicHuffmanCode(){
name="";
weight=0;
lc=-1;rc=-1;pa=-1;
}
}
publicclassHuffman1 {
dist[j]=newdist;prev[j]=u;}}}}
(3)运行结果
3、题目三
(1)问题分析
设G=(V,E)是连通带权图,V={1,2,…,n}。构造G的最小生成树的Prim算法的基本思想是:首先置S{1},然后,只要S是V的真子集,就进行如下的贪心选择:选取满足条件i∈S,j∈V-S,且c[i][j]最小的边,将顶点j添加到S中。这个过程一直进行到S=V时为止。过程中所取到的边恰好构成G的一棵最小生成树。
实验三.哈夫曼编码的贪心算法设计

实验四 哈夫曼编码的贪心算法设计(4学时)[实验目的]1. 根据算法设计需要,掌握哈夫曼编码的二叉树结构表示方法;2. 编程实现哈夫曼编译码器;3. 掌握贪心算法的一般设计方法。
实验目的和要求(1)了解前缀编码的概念,理解数据压缩的基本方法;(2)掌握最优子结构性质的证明方法;(3)掌握贪心法的设计思想并能熟练运用(4)证明哈夫曼树满足最优子结构性质;(5)设计贪心算法求解哈夫曼编码方案;(6)设计测试数据,写出程序文档。
实验内容设需要编码的字符集为{d 1, d 2, …, dn },它们出现的频率为 {w 1, w 2, …, wn },应用哈夫曼树构造最短的不等长编码方案。
核心源代码#include <stdio.h>#include <stdlib.h>#include <string.h>typedef struct{unsigned int weight; //用来存放各个结点的权值unsigned int parent,LChild,RChild; //指向双亲、孩子结点的指针} HTNode, *HuffmanTree; //动态分配数组,存储哈夫曼树typedef char *HuffmanCode; //动态分配数组,存储哈夫曼编码∑=ji k k a//选择两个parent为0,且weight最小的结点s1和s2 void Select(HuffmanTree *ht,int n,int *s1,int *s2){int i,min;for(i=1; i<=n; i++){if((*ht)[i].parent==0){min=i;break;}}for(i=1; i<=n; i++){if((*ht)[i].parent==0){if((*ht)[i].weight<(*ht)[min].weight)min=i;}}*s1=min;for(i=1; i<=n; i++){if((*ht)[i].parent==0 && i!=(*s1)){min=i;break;}}for(i=1; i<=n; i++){if((*ht)[i].parent==0 && i!=(*s1)){if((*ht)[i].weight<(*ht)[min].weight)min=i;}}*s2=min;}//构造哈夫曼树ht,w存放已知的n个权值void CrtHuffmanTree(HuffmanTree *ht,int *w,int n) {int m,i,s1,s2;m=2*n-1; //总共的结点数*ht=(HuffmanTree)malloc((m+1)*sizeof(HTNode));for(i=1; i<=n; i++) //1--n号存放叶子结点,初始化{(*ht)[i].weight=w[i];(*ht)[i].LChild=0;(*ht)[i].parent=0;(*ht)[i].RChild=0;}for(i=n+1; i<=m; i++) //非叶子结点的初始化{(*ht)[i].weight=0;(*ht)[i].LChild=0;(*ht)[i].parent=0;(*ht)[i].RChild=0;}printf("\n哈夫曼树为: \n");for(i=n+1; i<=m; i++) //创建非叶子结点,建哈夫曼树{ //在(*ht)[1]~(*ht)[i-1]的范围内选择两个parent为0且weight最小的结点,其序号分别赋值给s1、s2 Select(ht,i-1,&s1,&s2);(*ht)[s1].parent=i;(*ht)[s2].parent=i;(*ht)[i].LChild=s1;(*ht)[i].RChild=s2;(*ht)[i].weight=(*ht)[s1].weight+(*ht)[s2].weight;printf("%d (%d, %d)\n",(*ht)[i].weight,(*ht)[s1].weight,(*ht)[s2].weight);}printf("\n");}//从叶子结点到根,逆向求每个叶子结点对应的哈夫曼编码void CrtHuffmanCode(HuffmanTree *ht, HuffmanCode *hc, int n){char *cd; //定义的存放编码的空间int a[100];int i,start,p,w=0;unsigned int c;hc=(HuffmanCode *)malloc((n+1)*sizeof(char *)); //分配n个编码的头指针cd=(char *)malloc(n*sizeof(char)); //分配求当前编码的工作空间cd[n-1]='\0'; //从右向左逐位存放编码,首先存放编码结束符for(i=1; i<=n; i++) //求n个叶子结点对应的哈夫曼编码{a[i]=0;start=n-1; //起始指针位置在最右边for(c=i,p=(*ht)[i].parent; p!=0; c=p,p=(*ht)[p].parent) //从叶子到根结点求编码{if( (*ht)[p].LChild==c){cd[--start]='1'; //左分支标1a[i]++;}else{cd[--start]='0'; //右分支标0a[i]++;}}hc[i]=(char *)malloc((n-start)*sizeof(char)); //为第i个编码分配空间strcpy(hc[i],&cd[start]); //将cd复制编码到hc}free(cd);for(i=1; i<=n; i++)printf(" 权值为%d的哈夫曼编码为:%s\n",(*ht)[i].weight,hc[i]);for(i=1; i<=n; i++)w+=(*ht)[i].weight*a[i];printf(" 带权路径为:%d\n",w);}void main(){HuffmanTree HT;HuffmanCode HC;int *w,i,n,wei;printf("**哈夫曼编码**\n" );printf("请输入结点个数:" );scanf("%d",&n);w=(int *)malloc((n+1)*sizeof(int)); printf("\n输入这%d个元素的权值:\n",n); for(i=1; i<=n; i++){printf("%d: ",i);fflush(stdin);scanf("%d",&wei);w[i]=wei;}CrtHuffmanTree(&HT,w,n); CrtHuffmanCode(&HT,&HC,n);}实验结果实验体会哈夫曼编码算法:每次将集合中两个权值最小的二叉树合并成一棵新二叉树,n-1次合并后,成为最终的一棵哈夫曼树。
哈弗曼树编码实验报告

一、实验目的(1)了解前缀编码的概念,理解数据压缩的基本方法;(2)掌握最优子结构性质的证明方法;(3)掌握贪心法的设计思想并能熟练运用。
二、实验原理(1)证明哈夫曼树满足最优子结构性质;证明:设C为一给定的字母表,其中每个字母c∈C都定义有频度f[c]。
设x和y是C中具有最低频度的两个字母。
并设D为字母表移去x和y,再加上新字符z后的字母表,D=C-{x,y}∪{z};如C一样为D 定义f,其中f[z]=f[x]+f[y]。
设T为表示字母表D上最优前缀编码的任意一棵树。
那么,将T中的叶子节点z替换成具有x和y孩子的内部节点所得到的树T,表示字母表C上的一个最优前缀编码。
(2)设计贪心算法求解哈夫曼编码方案;解:哈夫曼编码是以贪心法为基础的,可以从最优子结构中求得问题的解。
所以,需要从一个问题中选出一个当前最优的解,再把这些解加起来就是最终问题的解。
可以构造一个优先队列priority_queue,每次求解子问题的解时,从优先级队列priority_queue中选取频率最小的两个字母(x、y)进行合并得到一个新的结点z,把x与y从优先级队列priority_queue中弹出,把压入到优先级队列priority_queue中。
如此反复进行,直到优先级队列priority_queue中只有一个元素(根节点)为止。
(3)设计测试数据,写出程序文档。
表四:表二中各元素的哈夫曼编码三、实验设备1台PC及VISUAL C++6.0软件四、代码#include <iostream>#include <queue>#include <vector>#include <iomanip>#include <string>#include<cctype>using namespace std;structcodeInformation{double priority;charcodeName;intlchild,rchild,parent;bool test;bool operator < (constcodeInformation& x) const {return !(priority<x.priority);} };bool check(vector<codeInformation>qa,const char c){for (int i=0 ;i<(int)(qa.size());i++){if(qa[i].codeName==c) return true;} return false;}voidaline(char c,int n){for (int i=0;i<n;i++)cout<<c;}intInputElement(vector<codeInformation>* Harffcode,priority_queue<codeInformation>* pq) {int i=1,j=1;codeInformation wk;while(i){aline('-',80);cout<<"请输入第"<<j<<"个元素的字符名称(Ascll码):"<<flush;cin>>wk.codeName;while(check(* Harffcode,wk.codeName)){cout<<"字符已存在,请输入一个其他的字符:";cin>>wk.codeName;}cout<<"请输入第"<<j<<"个元素的概率(权值):"<<flush;cin>>wk.priority;wk.lchild=wk.rchild=wk.parent=-1;wk.test=false;Harffcode->push_back(wk);pq->push(wk);j++;cout<<"1…………继续输入下一个元素信息!"<<endl;cout<<"2…………已完成输入,并开始构造哈夫曼树!"<<endl;cin>>i;if (i==2) i=0;}int count=1;j=Harffcode->size();int selectElement(vector<codeInformation>*,priority_queue<codeInformation>*);for (int k=j;k<2*j-1;k++){aline('*',80);cout<<"第"<<count<<"次合并:"<<endl;int i1=selectElement(Harffcode,pq);int i2=selectElement(Harffcode,pq);(*Harffcode)[i1].parent=(*Harffcode)[i2].parent=k;wk.lchild=wk.rchild=wk.parent=-1;wk.codeName='#';(*Harffcode).push_back(wk);wk.priority=(*Harffcode)[k].priority=(*Harffcode)[i1].priority+(*Harffcode)[i2].priority;(*Harffcode)[k].lchild=i1;(*Harffcode)[k].rchild=i2;wk.test=false;pq->push(wk); c ount++;cout<<"所合成的节点名称:#(虚节点)\t"<<"概率(权值):"<<(*Harffcode)[k].priority<<endl;}aline('*',80);return j;}voidshowChar(const char c){if(isspace(c))cout<<"#";cout<<c;}int selectElement(vector<codeInformation>*Harffcode,priority_queue<codeInformation>*qurgh){for (int i=0;i<(int)(*Harffcode).size();i++){if (((*Harffcode)[i].priority==(*qurgh).top().priority)&&((*Harffcode)[i].test==false)){cout<<"所选择的节点的信息:"<<"频率(权值):"<<setw(5)<<(*qurgh).top().priority<<"\t 名为:";showChar((*qurgh).top().codeName);cout<<endl;(*qurgh).pop();(*Harffcode)[i].test=true;return i;}}}voidhuffmanCode(vector<codeInformation>Harffcode,int n){for (int i1=0;i1<(int)Harffcode.size();i1++){cout<<"array["<<i1<<"]的概率(权值):"<<Harffcode[i1].priority<<"\t"<<"名为:";showChar(Harffcode[i1].codeName);cout<<"\t父节点的数组下标索引值:"<<Harffcode[i1].parent<<endl;}aline('&',80);for (int i=0;i<n;i++){string s=" "; int j=i;while(Harffcode[j].parent>=0){if (Harffcode[Harffcode[j].parent].lchild==j) s=s+"0";else s=s+"1";j=Harffcode[j].parent;}cout<<"\n概率(权值)为:"<<setw(8)<<Harffcode[i].priority<<" 名为:";showChar(Harffcode[i].codeName);cout<<"的符号的编码是:";for (int i=s.length();i>0;i--)cout<<s[i-1];}}voidchoise(){cout<<endl;aline('+',80);cout<<"\n1……………………继续使用该程序"<<endl;cout<<"2……………………退出系统"<<endl;}void welcome(){cout<<"\n"<<setw(56)<<"欢迎使用哈夫曼编码简易系统\n"<<endl;}int main(){welcome();system("color d1");int i=1,n;vector<codeInformation>huffTree; priority_queue<codeInformation>qpTree;while(i!=2){n=InputElement(&huffTree,&qpTree);huffmanCode(huffTree, n);choise();cin>>i;huffTree.clear();while(qpTree.empty()) qpTree.pop();}return 0;}五、实验过程原始记录( 测试数据、图表、计算等)程序测试结果及分析:图(2)输入第一组测试数据开始输入第一组测试数据,该组数据信息如表一所示。
哈夫曼编码贪心算法

哈夫曼编码贪心算法
一、哈夫曼编码
哈夫曼编码(Huffman Coding)是一种著名的数据压缩算法,也称作霍夫曼编码,由美国信息论家杰弗里·哈夫曼在1952年提出[1]。
哈夫曼编码可以有效地将资料压缩至最小,它的原理是将资料中出现频率最高的字元编码为最短的码字,而出现频率低的字元编码为较长的码字,从而显著提高了信息的保密性和容量。
二、贪心算法
贪心算法(Greedy Algorithm)是一种计算机算法,它试图找到一种满足条件的最佳解决方案,通常每一步都是做出在当前状态下最佳的选择,而不考虑将来可能发生的结果。
哈夫曼编码贪心算法是利用贪心算法来实现哈夫曼编码的。
该算法的步骤如下:
1. 首先统计出每一个字符出现的次数,并以此建立森林。
森林
中的每一棵树都用一个节点表示,每个节点的数值为字符出现的次数。
2. 从森林中挑选出两个出现次数最少的字符,将它们作为左右
子树合成一颗新的树,新树的根节点的数值为两个孩子节点的和。
3. 将新树加入森林中,并删除左右子树对应的原节点。
4. 重复上述步骤,直到森林中只剩一颗树,这颗树就是哈夫曼树。
5. 从哈夫曼树根节点出发,逐层往下搜索,左子节点编码为“0”,右子节点编码为“1”,最终得到每个字符的哈夫曼编码。
贪心算法设计与应用

实验报告课程算法设计与分析实验实验名称贪心算法设计与应用第 1 页一、实验目的理解贪心算法的基本原理,掌握贪心算法设计的基本方法及其应用;二、实验内容(一)Huffman编码和译码问题:1.问题描述给定n个字符在文件中的出现频率,利用Huffman树进行Huffman编码和译码。
设计一个程序实现:1.输入含n(n<=10)个字符的字符集S以及S中各个字符在文件中的出现频率,建立相应的Huffman树,求出S中各个字符的Huffman编码。
2.输入一个由S中的字符组成的序列L,求L的Huffman 编码。
3. 输入一个二进制位串B,对B进行Huffman译码,输出对应的字符序列;若不能译码,则输出无解信息。
提示:对应10 个字符的Huffman树的节点个数<211。
2.测试数据Inputn=5字符集合S={a, b, c, d, e},对应的频率分别为a: 20b: 7c: 10d: 4e: 18字符序列L=ebcca二进制位串B=01100111010010OutputS中各个字符的Huffman编码:(设Huffman树中左孩子的权<=右孩子的权)a: 11b: 010c: 00d: 011e: 10L的Huffman 编码:10010000011B对应的字符序列: dcaeeb若输入的B=01111101001,则无解(二) 加油问题(Problem Set 1702):1.问题描述一个旅行家想驾驶汽车从城市A到城市B(设出发时油箱是空的)。
给定两个城市之间的距离dis、汽车油箱的容量c、每升汽油能行驶的距离d、沿途油站数n、油站i离出发点的距离d[i]以及该站每升汽油的价格p[i],i=1,2,…,n。
设d[1]=0<d[2]<…<d[n]。
要花最少的油费从城市A到城市B,在每个加油站应加多少油,最少花费为多少?2.具体要求Input输入的第一行是一个正整数k,表示测试例个数。
贪心算法实现Huffman编码

算法分析与设计实验报告第次实验附录:完整代码#include <iostream>#include <string>#include<stdio.h>#include <time.h>#include <iomanip>#include <vector>#include<algorithm>using namespace std;class Huffman{public:char elementChar;//节点元素int weight;//权重char s;//哈夫曼编码Huffman* parent;//父节点Huffman* leftChild;//左孩子Huffman* rightChild;//右孩子public:Huffman();Huffman(char a, int weight);bool operator < (const Huffman &m)const { return weight < m.weight;} };Huffman::Huffman(){this->s = ' ';this->elementChar = '*';//非叶子节点this->parent = this->leftChild = this->rightChild = NULL;}Huffman::Huffman(char a, int weight):elementChar(a),weight(weight) {this->s = ' ';this->elementChar = '*';//非叶子节点this->parent = this->leftChild = this->rightChild = NULL;}//递归输出哈夫曼值void huffmanCode(Huffman & h){if(h.leftChild == NULL && h.rightChild == NULL){//如果是叶子节点,输出器哈夫曼编码string s;Huffman temp = h;while(temp.parent != NULL){s = temp.s + s;temp = *temp.parent;}cout << h.elementChar << "的哈夫曼编码是:" << s << endl; return;}//左孩子huffmanCode(*h.leftChild);//右孩子huffmanCode(*h.rightChild);}int main(){int l,p=0;double q=0.0;clock_t start,end,over;start=clock();end=clock();over=end-start;start=clock();string huffmanStr;cout << "请输入一串字符序列:" << endl;cin >> huffmanStr;//得到字符串信息int i=0,j,n,m[100],h,k=0;char cha[100];n = huffmanStr.length();cout << "字符串总共有字符" << n << "个" << endl;for(int i = 0; i < n; i++){j = 0; h = 0;while(huffmanStr[i] != huffmanStr[j])j++;if(j == i){cha[k] = huffmanStr[i];cout << "字符" << cha[k] << "出现";}//如果j !=i 则略过此次循环elsecontinue;for(j = i; j < n; j++){if(huffmanStr[i] == huffmanStr[j])h++;}cout << h << "次" << endl;m[k] = h;k++;}//哈夫曼编码Huffman huffmanTemp;vector < Huffman > huffmanQueue;//初始化队列for(int i = 0; i < k; i++){huffmanTemp.elementChar = cha[i];huffmanTemp.weight = m[i];huffmanQueue.push_back(huffmanTemp);}//得到哈夫曼树所有节点int huffmanQueue_index = 0;sort(huffmanQueue.begin(), huffmanQueue.end());while(huffmanQueue.size() < 2 * k - 1){//合成最小两个节点的父节点huffmanTemp.weight = huffmanQueue[huffmanQueue_index].weight + huffmanQueue[huffmanQueue_index + 1].weight;huffmanQueue[huffmanQueue_index].s = '0';huffmanQueue[huffmanQueue_index + 1].s = '1';huffmanTemp.elementChar = '*';//将父节点加入队列huffmanQueue.push_back(huffmanTemp);sort(huffmanQueue.begin(), huffmanQueue.end());huffmanQueue_index += 2;}//把所有节点构造成哈夫曼树int step = 0;//步长while(step + 2 < 2 * k){for(int j = step + 1; j <= huffmanQueue.size(); j++){if(huffmanQueue[j].elementChar == '*' && huffmanQueue[j].leftChild == NULL && (huffmanQueue[j].weight == huffmanQueue[step].weight + huffmanQueue[step+1].weight)){huffmanQueue[j].leftChild = &huffmanQueue[step];huffmanQueue[j].rightChild = &huffmanQueue[step+1];huffmanQueue[step].parent = huffmanQueue[step+1].parent = &huffmanQueue[j]; break;}}step += 2;}//序列最后一个元素,即哈弗曼树最顶端的节点huffmanTemp = huffmanQueue.back();huffmanCode(huffmanTemp);for(l=0;l<1000000000;l++)p=p+l;end=clock();printf("The time is %6.3f",(double)(end-start-over)/CLK_TCK);return 0;}。
哈夫曼编码的贪心算法时间复杂度

哈夫曼编码的贪心算法时间复杂度哈夫曼编码的贪心算法时间复杂度在信息技术领域中,哈夫曼编码是一种被广泛应用的数据压缩技术,它利用了贪心算法的思想来设计。
贪心算法是一种在每一步都选择当前状态下最优解的方法,从而希望通过一系列局部最优解达到全局最优解。
在哈夫曼编码中,这个想法被巧妙地运用,从而有效地实现了数据的高效压缩和解压缩。
哈夫曼编码是由大名鼎鼎的大卫·哈夫曼(David A. Huffman)在1952年提出的,它通过将频率最高的字符赋予最短的编码,最低的字符赋予最长的编码,从而实现了对数据的高效压缩。
这种编码技术在通信领域、存储领域和计算机科学领域都有着广泛的应用,是一种非常重要的数据处理技术。
在哈夫曼编码的实现过程中,贪心算法的时间复杂度是非常重要的。
时间复杂度是用来衡量算法所需时间的数量级,通常使用大O记号(O(n))来表示。
对于哈夫曼编码的贪心算法来说,其时间复杂度主要取决于以下几个步骤:1. 需要对数据进行统计,以获取每个字符出现的频率。
这个步骤的时间复杂度是O(n),其中n表示字符的数量。
在实际应用中,这个步骤通常由哈希表或统计排序来实现,因此时间复杂度可以控制在O(n)的数量级。
2. 接下来,需要构建哈夫曼树。
哈夫曼树是一种特殊的二叉树,它的构建过程需要将频率最低的两个节点合并成一个新的节点,然后再对新节点进行排序。
这个过程会持续n-1次,直到所有节点都被合并到一棵树中。
构建哈夫曼树的时间复杂度是O(nlogn),其中n表示字符的数量。
3. 根据哈夫曼树生成每个字符的编码。
这个过程涉及到对哈夫曼树进行遍历,并记录下每个字符对应的编码。
由于哈夫曼树的特性,每个字符的编码可以通过从根节点到叶子节点的路径来得到。
这个步骤的时间复杂度是O(n),因为对于每个字符都需要进行一次遍历。
哈夫曼编码的贪心算法时间复杂度主要由构建哈夫曼树的步骤决定,为O(nlogn)。
这意味着在实际应用中,哈夫曼编码的运行时间随着字符数量的增加而增加,并且增长速度为nlogn的数量级。
贪心算法程序设计

贪心算法程序设计贪心算法程序设计1. 什么是贪心算法贪心算法(Greedy Algorithm)是一种常见的算法思想,它在每一步选择中都采取当前状态下的最优选择,从而希望最终达到全局最优解。
贪心算法的核心思想是局部最优解能导致全局最优解。
2. 贪心算法的基本步骤贪心算法的基本步骤如下:1. 定义问题的优化目标。
2. 将问题分解成子问题。
3. 选择当前最优的子问题解,将子问题的解合并成原问题的解。
4. 检查是否达到了问题的优化目标,如果没有达到,则回到第二步,继续寻找下一个最优子问题解。
5. 在所有子问题解合并成原问题解后,得到问题的最优解。
3. 贪心算法的应用场景贪心算法的应用非常广泛,几乎可以用于解决各种优化问题。
以下几个常见的应用场景:1. 零钱找零问题:给定一定面额的纸币和硬币,如何找零使得所需纸币和硬币的数量最小?2. 区间调度问题:给定一些活动的开始时间和结束时间,如何安排活动使得可以办理的活动数量最大?3. 背包问题:给定一些具有重量和价值的物品,如何选择物品使得背包的总价值最大?4. 最小树问题:给定一个带权无向图,如何找到一棵树,使得它的边权之和最小?5. 哈夫曼编码问题:给定一组字符和相应的频率,如何构造一个满足最低编码长度限制的二进制编码?4. 贪心算法的优缺点贪心算法的优点是简单、高效,可以快速得到一个近似最优解。
而且对于一些问题,贪心算法能够得到全局最优解。
贪心算法的缺点在于它不一定能够得到全局最优解,因为在每一步只考虑局部最优解,无法回溯到之前的选择。
5. 贪心算法的程序设计在使用贪心算法进行程序设计时,通常需要以下几个步骤:1. 定义问题的优化目标。
2. 将问题分解成子问题,并设计子问题的解决方案。
3. 设计贪心选择策略,选择局部最优解。
4. 设计贪心算法的递推或迭代公式。
5. 判断贪心算法是否能够得到全局最优解。
6. 编写程序实现贪心算法。
6.贪心算法是一种常见的算法思想,它在每一步选择中都采取当前状态下的最优选择,从而希望最终达到全局最优解。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
@
实验四 哈夫曼编码的贪心算法设计(4学时)
[实验目的]
1. 根据算法设计需要,掌握哈夫曼编码的二叉树结构表示方法;
2. 编程实现哈夫曼编译码器;
3. 掌握贪心算法的一般设计方法。
实验目的和要求
(1)了解前缀编码的概念,理解数据压缩的基本方法;
(2)掌握最优子结构性质的证明方法;
】
(3)掌握贪心法的设计思想并能熟练运用
(4)证明哈夫曼树满足最优子结构性质;
(5)设计贪心算法求解哈夫曼编码方案;
(6)设计测试数据,写出程序文档。
实验内容 设需要编码的字符集为{d 1, d 2, …, dn },它们出现的频率为 {
w 1, w 2, …, wn
},应用哈夫曼树构造最短的不等长编码方案。
核心源代码
~
#include <>
#include <>
#include <>
typedef struct
{
unsigned int weight; arent==0)
{
@
min=i;
break;
}
}
for(i=1; i<=n; i++)
{
if((*ht)[i].parent==0)
{
!
if((*ht)[i].weight<(*ht)[min].weight)
min=i;
}
}
*s1=min;
∑=j
i k k
a
for(i=1; i<=n; i++)
{
~
if((*ht)[i].parent==0 && i!=(*s1))
{
min=i;
break;
}
}
for(i=1; i<=n; i++)
{
%
if((*ht)[i].parent==0 && i!=(*s1))
{
if((*ht)[i].weight<(*ht)[min].weight)
min=i;
}
}
*s2=min;
}
-
eight=w[i];
(*ht)[i].LChild=0;
(*ht)[i].parent=0;
(*ht)[i].RChild=0;
}
for(i=n+1; i<=m; i++) eight=0;
(*ht)[i].LChild=0;
\
(*ht)[i].parent=0;
(*ht)[i].RChild=0;
}
printf("\n哈夫曼树为: \n");
for(i=n+1; i<=m; i++) arent=i;
(*ht)[s2].parent=i;。
(*ht)[i].LChild=s1;
(*ht)[i].RChild=s2;
(*ht)[i].weight=(*ht)[s1].weight+(*ht)[s2].weight;
printf("%d (%d, %d)\n",(*ht)[i].weight,(*ht)[s1].weight,(*ht)[s2].weight); }
printf("\n");
}
>
arent; p!=0; c=p,p=(*ht)[p].parent) Child==c) {
cd[--start]='1'; eight,hc[i]);
for(i=1; i<=n; i++)
w+=(*ht)[i].weight*a[i];
printf(" 带权路径为:%d\n",w);
>
}
void main()
{
HuffmanTree HT;
HuffmanCode HC;
int *w,i,n,wei;
—
printf("**哈夫曼编码**\n" );
printf("请输入结点个数:" );
scanf("%d",&n);
w=(int *)malloc((n+1)*sizeof(int));
printf("\n输入这%d个元素的权值:\n",n);
for(i=1; i<=n; i++)
{
)
printf("%d: ",i);
fflush(stdin);
scanf("%d",&wei);
w[i]=wei;
}
CrtHuffmanTree(&HT,w,n);
CrtHuffmanCode(&HT,&HC,n);
}
实验结果
实验体会
哈夫曼编码算法:每次将集合中两个权值最小的二叉树合并成一棵新二叉树,n-1次合并后,成为最终的一棵哈夫曼树。
这既是贪心法的思想:从某一个最初状态出发,根据当前的局部最优策略,以满足约束方程为条件,以使目标函数最快(或最慢)为原则,在候选集合中进行一系列的选择,以便尽快构成问题的可行解。
每次选择两个权值最小的二叉树时,规定了较小的为左子树。