用C语言实现哈夫曼树和生成哈夫曼编码,首先生成哈夫曼树,哈夫曼树是从中选取权值最小的两个进行相加,将这两个分别做为生成的左子树和右子树,左子树要比右子树小。然后将相加得到的值从新放入,然后又从中找到最小的两个值,然后用这个两个值一直相加,直到只剩最后一个值,将这个值作为哈夫曼树的根。
生成哈夫曼编码,如果是左子树的话为0,右子树的话为1,从父节点还是往下找。然后这串代码就是哈夫曼编码。
上代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include<bits/stdc++.h>
using namespace std;
const int Lsize = 1000000;
typedef struct{
int order;//序号
char character;//字符值
int weight;//权重
int parent;
int lift_Child;
int right_Child;
int deep;
int code[100];//哈夫曼编码
}Nodetree,*HuffmanTree;
typedef struct node{
char symbol;
int quantity;
struct node *next;
}Node;
int getListSize(char *pStr){
int len=0;
char *start = pStr;
while(*start){
len++;
start++;
}
return len;
}
int getLIstLink(Node *head){
int a = 0;
Node *p = head->next;
while(p){
a++;
p = p->next;
}
return a;
};
//打印链表
void print(struct node *head){
struct node *p ;
printf("开始打印\n");
p=head->next ;
if(p == NULL){
printf("值为空\n");
}
while(p!=NULL){
printf(" %c",p->symbol);
printf(" %d\n",p->quantity);
p=p->next;
}
};
int QueryNOde(Node *head,char ch){
Node *p;
p = head->next;
while(p!=NULL){
if(p->symbol == ch){
p->quantity = p->quantity + 1;//字符存在节点加1
return 1;//这个字符已经存在
}
p = p->next;
}
return 0;//这个字符不存在
};
//生成权值
Node *createWeight(char *str){
Node *head , *q ,*p;
int list_size = getListSize(str);
q=head=(struct node*)malloc(sizeof(struct node));
for(int i = 0 ; i < list_size ; i++){
//printf("当前的值:%c\n",*str);
if(QueryNOde(head,*str)==1){//如果该数据已经存在,则节点加1
// printf("开始遍历\n");
// Node *boos = head = (struct node*)malloc(sizeof(struct node));
// printf("开始查找\n");
// while(boos){
// printf("进入查找\n");
// printf("当前遍历值为:%c\n",boos->symbol);
// if(boos->symbol == *str){
// printf("开始修改值\n");
// boos->quantity = boos->quantity + 1;
// printf("值相同\n");
// break;
// }
// boos = boos->next;
//}
} else{//生成新的权值
p = (struct node*)malloc(sizeof(struct node));
p->quantity = 1;
p->symbol = *str;
p->next = NULL;
q->next = p;
q = p;
//printf("值不同\n");
}
str++;
}
return head;
};
void createTree(HuffmanTree &root,int n,Node *head){
if(n<=0){
return;
}
Node *q;
q = head->next;
int length = 2*n - 1;
printf("n is %d\n",n);
int HFCode[100];//哈夫曼编码数组
root = new Nodetree[length+1];
//初始化哈夫曼树
for(int i = 1;i<=length;i++){
root[i].order = i;
root[i].character = 0;
root[i].parent = 0;
root[i].lift_Child = 0;
root[i].right_Child = 0;
}
//给哈夫曼树赋值
for(int i = 1;i<=n;i++){
root[i].character = q->symbol;
root[i].weight = q->quantity;
q = q->next;
}
//开始建立哈夫曼树
for(int i = n+1; i <=length; i++){ //进行 n-1 次循环建立哈夫曼树
//k1表示森林中具有最小权值的树根结点的下标,k2为次最小的下标
int k1 = -1 , k2;
for(int j = 0; j < i; j++){
if ( root[j].parent == 0 && k1 == -1 && root[j].weight > 0){
k1 = j;
continue;
}
if (root[j].parent == 0 && root[j].weight > 0){
k2 = j;
break;
}
}
//将指针数组中的指针指向的最小值赋值给索引号为k1的,次小值赋值给索引号为k2的
for (int j = k2; j < i; j++){
if(root[j].parent == 0 ){
if(root[j].weight < root[k1].weight){
k2 = k1;
k1 = j;
}else if(root[j].weight < root[k2].weight){
k2 = j;
}
}
}
//开始生成新的哈夫曼树节点
root[k1].parent = i;
root[k2].parent = i;
// printf(" i is:%d\n",i);
// printf("k1 is :%d\n",k1);
// printf("k2 is :%d\n",k2);
// printf(" k1 weight is:%d\n",root[k1].weight);
// printf(" k2 weight is:%d\n",root[k2].weight);
root[i].order = i;
root[i].lift_Child = k1;
root[i].right_Child = k2;
root[i].weight = root[k1].weight + root[k2].weight;
}
int start;
// HFCode[n-1]='\0';
//生成哈夫曼编码
for(int i = 1;i<=n;i++){
start = 0;
int deep = 0;//节点的深度
int c = i;
int f = root[i].parent;
while(f!=0){
//printf("tart is:%d\n",start);
if(root[f].lift_Child == c){
root[i].code[start] = 0;//如果为左子树就为0
}else{
root[i].code[start] = 1;//右子树就为1
}
deep++;
start++;
c = f;
f = root[f].parent;
}
root[i].deep = deep;
// printf("code is:%d\n",root[i].code[start]);
}
};
//void CreatHFCode(Nodetree *root,)
//打印哈夫曼树的表态结构
void printTree(Nodetree *root,int n){
int length = 2*n -1;
for(int i = 1 ;i<=length;i++){
printf("order is %d character is %c" " parent is %d LiftC is %d rightC is %d weight is %d deep is %d ",root[i].order, root[i].character, root[i].parent,root[i].lift_Child,root[i].right_Child, root[i].weight,root[i].deep);
int deep = root[i].deep;
printf("HFCode is :");
for(int j=deep-1;j>=0;j--){
printf("%d",root[i].code[j]);
}
printf("\n");
}
};
void QueryCOde(Nodetree *root,int n){
int query_list[100];//哈夫曼编码整数数组
int flag ;//哈夫曼编码匹配判断标志
int c;
int code_Size;
char query_char[100];//用来接收哈夫曼编码
scanf("%s",&query_char);
//printf("%s\n",query_char);
code_Size = getListSize(query_char);//输入的哈夫曼编码长度
//将输入的哈夫曼编码有字符数组转换为整数数组
for(int i = 0;i<code_Size;i++){
c = query_char[i]-'0';
query_list[i] = c;
// printf("n is:%d\n",c);
}
// for(int i=0;i<code_Size;i++){
// printf("%d ",query_list[i]);
// }
for(int i=1;i<=n;i++){
int deep = root[i].deep;
int j ;
//若哈夫曼的深度和输入的哈夫曼编码长度相同则开始查找
if(deep==code_Size){
//printf("deep is:%d code_size is:%d\n",deep,code_Size);
j=0;
int code = code_Size-1;
deep--;
//开始匹配值
flag = i;
while(deep>=0){
// printf("开始匹配deep %d\n",deep);
if(root[i].code[j]!=query_list[code]){
//printf("值不相同\n");
flag = -1;
break;
}
j++;
code--;
//printf("%d deep is %d\n",i,deep);
deep--;
}
}
//判断是否找到对应的权重的值
// printf("deep is:%d\n",deep);
if(deep<0){
flag = i;
i = n+1;
}
}
// printf("flag is:%d\n",flag);
if(flag>0){
printf("翻译结果值:%c\n",root[flag].character);
}
else{
printf("没有与编码匹配的数据值\n");
}
};
int main()
{
int Link_size ;
struct node *head;
Nodetree *root;
char input_list[Lsize];
printf("........................功能列表...................\n");
printf(".............. 输入报文 ................\n");
printf(".............. 打印频度 ................\n");
printf(".............. 建立哈夫曼树 ................\n");
printf(".............. 翻译报文 ................\n");
//printf(".............. 5.退出 ................\n");
printf("..............输入想要赋值的字符串\n");
scanf("%s",&input_list);
gets(input_list);
printf("%s\n",input_list);
head = createWeight(input_list);
printf("..............出现频度为\n");
print(head);
Link_size = getLIstLink(head);
printf("..............链表长度为:%d\n",Link_size);
createTree(root,Link_size,head);
printTree(root,Link_size);
int flag = 1;
while(flag==1){
printf("..............输入你想要查找的代码\n");
QueryCOde(root,Link_size);
printf("..............想继续查找输入1,不想输入0\n");
scanf("%d",&flag);
}
}
代码里面有备注,不清楚的可以留言,有错误的欢迎指出。