5678: 数据结构实验:哈夫曼树和编码
Posted qq-1585047819
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了5678: 数据结构实验:哈夫曼树和编码相关的知识,希望对你有一定的参考价值。
描述
当用 n 个结点(都做叶子结点且都有各自的权值)试图构建一棵树时,如果构建的这棵树的带权路径长度最小,称这棵树为“最优二叉树”,有时也叫“赫夫曼树”或者“哈夫曼树”。
现给定若干权值,请构建一棵哈夫曼树,并输出各个权值对应的哈夫曼编码长度。
哈夫曼树中的结点定义如下:
//哈夫曼树结点结构
typedef struct
{
int weight;//结点权重
int parent, left, right;//父结点、左孩子、右孩子在数组中的位置下标
}HTNode, *HuffmanTree;
//动态二维数组,存储哈夫曼编码
typedef char ** HuffmanCode;
部分代码已完成,请补充完整,提交时请勿包含给定代码。
//打印哈夫曼编码的函数 void PrintHuffmanCode(HuffmanCode htable, int *w, int n) { printf("Huffman code:\n"); for(int i = 1; i <= n; i++) printf("%d(%d)\n",w[i-1], strlen(htable[i])); } int main() { int w[100], n, i; scanf("%d", &n); for(i=0;i<n;i++) scanf("%d", &w[i]); HuffmanTree htree; HuffmanCode htable; CreateHuffmanTree(htree, w, n); HuffmanCoding(htree, htable, n); PrintHuffmanCode(htable,w, n); return 0; }
输入
输入数据第一行为n(不超过100),接下来有n个正整数,表示权值。
输出
按照输入权值顺序输出相应的哈夫曼编码的长度,格式见样例。
样例输入
样例输出
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef struct 5 { 6 int weight;//结点权重 7 int parent, left, right;//父结点、左孩子、右孩子在数组中的位置下标 8 }HTNode, *HuffmanTree; 9 typedef char ** HuffmanCode; 10 11 void select(HuffmanTree htree,int n, int *s1,int *s2){ 12 int minn; 13 for(int i=1;i<=n;i++){ 14 if((htree)[i].parent==0){ //如果此结点的父亲没有,那么把结点号赋值给 min,跳出循环 15 minn=i; 16 break; 17 } 18 } 19 for(int i=1;i<=n;i++){ //找出权值最小的 20 if((htree)[i].parent==0){ 21 if((htree)[i].weight<(htree)[minn].weight){ 22 minn=i; 23 } 24 } 25 } 26 *s1=minn; //编号 27 for(int i=1;i<=n;i++){ 28 if((htree)[i].parent==0&&i!=(*s1)){ //如果此结点的父亲没有,那么把结点号赋值给 min,跳出循环 29 minn=i; 30 break; 31 } 32 } 33 for(int i=1;i<=n;i++){ 34 if((htree)[i].parent==0&&i!=(*s1)){ 35 if((htree)[i].weight<(htree)[minn].weight){ 36 minn=i; 37 } 38 } 39 } 40 *s2=minn; //找出两个编号最小的 41 } 42 43 void CreateHuffmanTree(HuffmanTree &htree,int w[],int n){ 44 if(n<=1) return; // 如果只有一个编码就相当于 0 45 int m=2*n-1; //哈夫曼树度为2或为0 总结点树为2*n-1; 46 int s1,s2; //s1 和 s2 为两个当前结点里,要选取的最小权值的结点 47 htree=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); 48 for(int i=1;i<=n;i++){ //1--n号存放叶子结点,初始化叶子结点,结构数组来初始化每个叶子结点 49 (htree)[i].weight=w[i-1]; 50 (htree)[i].parent=0; 51 (htree)[i].left=0; 52 (htree)[i].right=0; 53 } 54 for(int i=n+1;i<=m;i++){ //非叶子结点的初始化 55 (htree)[i].weight=0; 56 (htree)[i].parent=0; 57 (htree)[i].left=0; 58 (htree)[i].right=0; 59 } 60 for(int i=n+1;i<=m;i++){ //创建非叶子结点,建哈夫曼树 61 select(htree, i-1, &s1, &s2); //再前面有权值里面选出两个最小的构建二叉树 62 (htree)[s1].parent=i; 63 (htree)[s2].parent=i; 64 (htree)[i].left=s1; 65 (htree)[i].right=s2; 66 (htree)[i].weight=(htree)[s1].weight+(htree)[s2].weight; 67 } 68 } 69 70 void HuffmanCoding(HuffmanTree &htree,HuffmanCode &htable,int n){ 71 htable=(HuffmanCode)malloc((n+1)*sizeof(char*)); 72 char *cd = (char *)malloc(n*sizeof(char)); 73 cd[n-1]=‘\0‘; 74 for(int i=1;i<=n;i++){ //从叶子节点开始 75 //从叶子结点出发,得到的哈夫曼编码是逆序的,需要在字符串数组中逆序存放 76 int start=n-1; 77 int c=i; 78 int j=htree[i].parent; 79 while(j!=0){ 80 // 如果该结点是父结点的左孩子则对应路径编码为 0,否则为右孩子编码为 1 81 if(htree[j].left==c){ 82 cd[--start]=‘0‘; 83 } 84 else cd[--start]=‘1‘; 85 c=j; 86 j=htree[j].parent; 87 } 88 //跳出循环后,cd 数组中从下标 start 开始,存放的就是该结点的哈夫曼编码 89 htable[i] = (char *)malloc((n-start)*sizeof(char)); 90 strcpy(htable[i],&cd[start]); 91 } 92 free(cd); 93 } 94 95 void PrintHuffmanCode(HuffmanCode htable, int *w, int n) 96 { 97 printf("Huffman code:\n"); 98 for(int i = 1; i <= n; i++) 99 printf("%d(%d)\n",w[i-1], strlen(htable[i])); 100 } 101 102 int main() 103 { 104 int w[100], n, i; 105 scanf("%d", &n); 106 for(i=0;i<n;i++) 107 scanf("%d", &w[i]); 108 HuffmanTree htree; 109 HuffmanCode htable; 110 CreateHuffmanTree(htree, w, n); 111 HuffmanCoding(htree, htable, n); 112 PrintHuffmanCode(htable,w, n); 113 return 0; 114 }
以上是关于5678: 数据结构实验:哈夫曼树和编码的主要内容,如果未能解决你的问题,请参考以下文章