标签:
3-5 HuffmanTree.c
1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <string.h> 4 typedef struct 5 { 6 int weight; //权值 7 int parent; //父结点序号 8 int left; //左子树序号 9 int right; //右子树序号 10 }HuffmanTree; 11 typedef char *HuffmanCode; //Huffman编码 12 void SelectNode(HuffmanTree *ht,int n,int *bt1,int *bt2) 13 //从1~x个结点选择parent结点为0,权重最小的两个结点 14 { 15 int i; 16 HuffmanTree *ht1,*ht2,*t; 17 ht1=ht2=NULL; //初始化两个结点为空 18 for(i=1;i<=n;++i) //循环处理1~n个结点(包括叶结点和非叶结点) 19 { 20 if(!ht[i].parent) //父结点为空(结点的parent=0) 21 { 22 if(ht1==NULL) //结点指针1为空 23 { 24 ht1=ht+i; //指向第i个结点 25 continue; //继续循环 26 } 27 if(ht2==NULL) //结点指针2为空 28 { 29 ht2=ht+i; //指向第i个结点 30 if(ht1->weight>ht2->weight) //比较两个结点的权重,使ht1指向的结点权重小 31 { 32 t=ht2; 33 ht2=ht1; 34 ht1=t; 35 } 36 continue; //继续循环 37 } 38 if(ht1 && ht2) //若ht1、ht2两个指针都有效 39 { 40 if(ht[i].weight<=ht1->weight) //第i个结点权重小于ht1指向的结点 41 { 42 ht2=ht1; //ht2保存ht1,因为这时ht1指向的结点成为第2小的 43 ht1=ht+i; //ht1指向第i个结点 44 }else if(ht[i].weight<ht2->weight){ //若第i个结点权重小于ht2指向的结点 45 ht2=ht+i; //ht2指向第i个结点 46 } 47 } 48 } 49 } 50 if(ht1>ht2){ //增加比较,使二叉树左侧为叶结点 51 *bt2=ht1-ht; 52 *bt1=ht2-ht; 53 }else{ 54 *bt1=ht1-ht; 55 *bt2=ht2-ht; 56 } 57 } 58 59 void CreateTree(HuffmanTree *ht,int n,int *w) 60 { 61 int i,m=2*n-1;//总的节点数 62 int bt1,bt2; //二叉树结点序与 63 if(n<=1) return ; //只有一个结点,无法创建 64 for(i=1;i<=n;++i) //初始化叶结点 65 { 66 ht[i].weight=w[i-1]; 67 ht[i].parent=0; 68 ht[i].left=0; 69 ht[i].right=0; 70 } 71 for(;i<=m;++i)//初始化后续结点 72 { 73 ht[i].weight=0; 74 ht[i].parent=0; 75 ht[i].left=0; 76 ht[i].right=0; 77 } 78 for(i=n+1;i<=m;++i) //逐个计算非叶结点,创建Huffman树 79 { 80 SelectNode(ht,i-1,&bt1,&bt2); //从1~i-1个结点选择parent结点为0,权重最小的两个结点 81 ht[bt1].parent=i; 82 ht[bt2].parent=i; 83 ht[i].left=bt1; 84 ht[i].right=bt2; 85 ht[i].weight=ht[bt1].weight+ht[bt2].weight; 86 } 87 } 88 void HuffmanCoding(HuffmanTree *ht,int n,HuffmanCode *hc)//,char *letters) 89 { 90 char *cd; 91 int start,i; 92 int current,parent; 93 cd=(char*)malloc(sizeof(char)*n);//用来临时存放一个字符的编码结果 94 cd[n-1]=‘\0‘; //设置字符串结束标志 95 for(i=1;i<=n;i++) 96 { 97 start=n-1; 98 current=i; 99 parent=ht[current].parent;//获取当前结点的父结点 100 while(parent) //父结点不为空 101 { 102 if(current==ht[parent].left)//若该结点是父结点的左子树 103 cd[--start]=‘0‘; //编码为0 104 else //若结点是父结点的右子树 105 cd[--start]=‘1‘; //编码为1 106 current=parent; //设置当前结点指向父结点 107 parent=ht[parent].parent; //获取当前结点的父结点序号 108 } 109 hc[i-1]=(char*)malloc(sizeof(char)*(n-start));//分配保存编码的内存 110 strcpy(hc[i-1],&cd[start]); //复制生成的编码 111 } 112 free(cd); //释放编码占用的内存 113 } 114 115 void Encode(HuffmanCode *hc,char *alphabet,char *str,char *code) 116 //将一个字符串转换为Huffman编码 117 //hc为Huffman编码表 ,alphabet为对应的字母表,str为需要转换的字符串,code返回转换的结果 118 { 119 120 int len=0,i=0,j; 121 code[0]=‘\0‘; 122 while(str[i]) 123 { 124 j=0; 125 while(alphabet[j]!=str[i]) 126 j++; 127 strcpy(code+len,hc[j]); //将对应字母的Huffman编码复制到code指定位置 128 len=len+strlen(hc[j]); //累加字符串长度 129 i++; 130 } 131 code[len]=‘\0‘; 132 } 133 134 void Decode(HuffmanTree *ht,int m,char *code,char *alphabet,char *decode) 135 //将一个Huffman编码组成的字符串转换为明文字符串 136 //ht为Huffman二叉树,m为字符数量,alphabet为对应的字母表,str为需要转换的字符串,decode返回转换的结果 137 { 138 int position=0,i,j=0; 139 m=2*m-1; 140 while(code[position]) //字符串未结束 141 { 142 for(i=m;ht[i].left && ht[i].right; position++) //在Huffman树中查找左右子树为空 ,以构造一个Huffman编码 143 { 144 if(code[position]==‘0‘) //编码位为0 145 i=ht[i].left; //处理左子树 146 else //编译位为 1 147 i=ht[i].right; //处理右子树 148 } 149 decode[j]=alphabet[i-1]; //得到一个字母 150 j++;//处理下一字符 151 } 152 decode[j]=‘\0‘; //字符串结尾 153 } 154 int main() 155 { 156 int i,n=4,m; 157 char test[]="DBDBDABDCDADBDADBDADACDBDBD"; 158 char code[100],code1[100]; 159 char alphabet[]={‘A‘,‘B‘,‘C‘,‘D‘}; //4个字符 160 int w[]={5,7,2,13} ;//4个字符的权重 161 HuffmanTree *ht; 162 HuffmanCode *hc; 163 m=2*n-1; 164 ht=(HuffmanTree *)malloc((m+1)*sizeof(HuffmanTree)); //申请内存,保存赫夫曼树 165 if(!ht) 166 { 167 printf("内存分配失败!\n"); 168 exit(0); 169 } 170 hc=(HuffmanCode *)malloc(n*sizeof(char*)); 171 if(!hc) 172 { 173 printf("内存分配失败!\n"); 174 exit(0); 175 } 176 177 CreateTree(ht,n,w); //创建赫夫曼树 178 HuffmanCoding(ht,n,hc); //根据赫夫曼树生成赫夫曼编码 179 for(i=1;i<=n;i++) //循环输出赫夫曼编码 180 printf("字母:%c,权重:%d,编码为 %s\n",alphabet[i-1],ht[i].weight,hc[i-1]); 181 182 Encode(hc,alphabet,test,code); //根据赫夫曼编码生成编码字符串 183 printf("\n字符串:\n%s\n转换后为:\n%s\n",test,code); 184 185 Decode(ht,n,code,alphabet,code1); //根据编码字符串生成解码后的字符串 186 printf("\n编码:\n%s\n转换后为:\n%s\n",code,code1); 187 getch(); 188 return 0; 189 }
标签:
原文地址:http://www.cnblogs.com/wozixiaoyao/p/5683130.html