哈夫曼树及哈夫曼编码和解码

哈夫曼树,又称最优树,是带权路径最小的树。
基本概念:
节点间的路径长度:两个节点间所包含的边的数目。
树的路径长度:从根到树中任意节点的路径长度之和。
权:将节点赋予一定的量值,该量值成为权。
树的带权路径长度:树中所有叶子结点的带权路径长度。

哈夫曼算法:给定一个保存权值的数组,求最优树的算法。对于此权值数组找出其中最小的权值和第二小的权值,用这两个权值创建树,并把这两个权值相加所得作为一个新权值放入到原数组中(注意:此时数组中已经去掉了刚才用过的权值),重复以上操作即可建立最优树。

哈弗曼编码和解码的优点不再赘述。

哈夫曼树的实现
1.建立结构体,比较简单

typedef struct Tree{
	struct Tree *left;
	struct Tree *right;
	int data;
}Tree;

2.利用权值数组创建哈夫曼树(代码注释已相对清晰)

Tree *create(int *a,int n){//对数组 a 进行实现哈夫曼树 a 中存放的为权值, n 为数组的长度
	Tree *tree;
	Tree **b;
	int i,j; 
	b = malloc(sizeof(Tree)*n);//动态一维数组的申请来保存权值 
	for(i = 0; i < n; i++){
		b[i] = malloc(sizeof(Tree));
		b[i]->data = a[i];
		b[i]->left = b[i]->right = NULL;
	} 
	//创建哈夫曼树
	for(i = 1; i < n; i++){
		int small1 = -1,small2;//small1指向权值最小,small2是第二小,其初始指向分别是数组的前两个元素
								//注意前两个元素并不一定是最小的和第二小的
		//下面一个 for 循环是让small1指向第一个权值,small2指向第二个权值 
		for(j = 0; j < n; j++){  
			if(b[j] != NULL && small1 == -1){
				small1 = j;
				continue;
			}
			if(b[j] != NULL){
				small2 = j;
				break;
			}
		} 
		//接下来就是对数组剩下的权值逐个与small1、small2比较,找出最小与第二小的权值 
		for(j = small2; j < n; j++){
			if(b[j] != NULL){
				if(b[j]->data < b[small1]->data){
					small2 = small1;
					small1 = j;
				}
				else if(b[small2]->data > b[j]->data){
					small2 = j;
				}
			}
		} 
		
		//由两个最小权值建立新树,tree 指向根节点 
		tree = malloc(sizeof(Tree));
		tree->data = b[small1]->data + b[small2]->data;
		tree->left = b[small1];
		tree->right = b[small2];
		
		//以下两步是用于重复执行 
		b[small1] = tree;
		b[small2] = NULL; 
		
	} 
	
	free(b);
	return tree;
}

3.打印哈夫曼树

//打印哈夫曼树 
void print(Tree *tree){
	if(tree){
		printf("%d ",tree->data);
		if(tree->left && tree->right){
			printf("(");
			print(tree->left);
			if(tree->right)
			printf(",");
			print(tree->right);
			printf(")");
		}
	}
}

4.获取哈夫曼树的带权路径长度

//获得哈夫曼树的带权路径长度
int getWeight(Tree *tree,int len){
	if(!tree)
	return 0;
	if(!tree->left && !tree->right)//访问到叶子结点 
	return tree->data * len;
	return getWeight(tree->left, len + 1) + getWeight(tree->right,len + 1);//访问到非叶子结点 
}

5.下面便是哈夫曼编码与解码,思路也较为简单

//哈夫曼编码 
void getCoding(Tree *tree,int len){
	if(!tree)
	return;
	static int a[20]; //定义静态数组a,保存每个叶子的编码,数组长度至少是树深度减一
	int i;
	if(!tree->left && !tree->right){
		printf(" %d  的哈夫曼编码为:",tree->data);
		for(i = 0; i < len; i++)
		printf("%d",a[i]);
		printf("\n");
	}
	else{//访问到非叶子结点时分别向左右子树递归调用,并把分支上的0、1编码保存到数组a ,的对应元素中,向下深入一层时len值增1 
		a[len] = 0;
		getCoding(tree->left, len + 1);
		a[len] = 1;
		getCoding(tree->right, len + 1);
		
	}
}

6.哈夫曼解码,比较容易实现
节点与左子节点之间记为 0 ,节点与右节点之间记为 1 ,如图
在这里插入图片描述

//哈夫曼解码
void Decoding(Tree *tree){
	printf("请输入要解码的字符串\n");
	char ch[100];//输入的待解码的字符串 
	gets(ch);
	int i;
	int num[100];//用于保存字符串对应的0 1 编码对应的节点 
	Tree *cur;
	for(i = 0; i < strlen(ch); i++){
		if(ch[i] == '0')
		num[i] = 0;
		else
		num[i] = 1;
	}
	
	if(tree){
		i = 0;
		while(i < strlen(ch)){
			cur = tree;
			while(cur->left && cur->right){
				
				if(num[i] == 0)
				cur = cur->left;
				else
				cur = cur->right;
				i++;
			}
			printf("%d",cur->data);
		}
		
	}
} 

完整代码如下

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct Tree{
	struct Tree *left;
	struct Tree *right;
	int data;
}Tree;


Tree *create(int *a,int n){//对数组 a 进行实现哈夫曼树 a 中存放的为权值, n 为数组的长度
	Tree *tree;
	Tree **b;
	int i,j; 
	b = malloc(sizeof(Tree)*n);//动态一维数组的申请来保存权值 
	for(i = 0; i < n; i++){
		b[i] = malloc(sizeof(Tree));
		b[i]->data = a[i];
		b[i]->left = b[i]->right = NULL;
	} 
	//创建哈夫曼树
	for(i = 1; i < n; i++){
		int small1 = -1,small2;//small1指向权值最小,small2是第二小,其初始指向分别是数组的前两个元素
								//注意前两个元素并不一定是最小的和第二小的
		//下面一个 for 循环是让small1指向第一个权值,small2指向第二个权值 
		for(j = 0; j < n; j++){  
			if(b[j] != NULL && small1 == -1){
				small1 = j;
				continue;
			}
			if(b[j] != NULL){
				small2 = j;
				break;
			}
		} 
		//接下来就是对数组剩下的权值逐个与small1、small2比较,找出最小与第二小的权值 
		for(j = small2; j < n; j++){
			if(b[j] != NULL){
				if(b[j]->data < b[small1]->data){
					small2 = small1;
					small1 = j;
				}
				else if(b[small2]->data > b[j]->data){
					small2 = j;
				}
			}
		} 
		
		//由两个最小权值建立新树,tree 指向根节点 
		tree = malloc(sizeof(Tree));
		tree->data = b[small1]->data + b[small2]->data;
		tree->left = b[small1];
		tree->right = b[small2];
		
		//以下两步是用于重复执行 
		b[small1] = tree;
		b[small2] = NULL; 
		
	} 
	
	free(b);
	return tree;
}

//打印哈夫曼树 
void print(Tree *tree){
	if(tree){
		printf("%d ",tree->data);
		if(tree->left && tree->right){
			printf("(");
			print(tree->left);
			if(tree->right)
			printf(",");
			print(tree->right);
			printf(")");
		}
	}
}

//获得哈夫曼树的带权路径长度
int getWeight(Tree *tree,int len){
	if(!tree)
	return 0;
	if(!tree->left && !tree->right)//访问到叶子结点 
	return tree->data * len;
	return getWeight(tree->left, len + 1) + getWeight(tree->right,len + 1);//访问到非叶子结点 
}

//哈夫曼编码 
void getCoding(Tree *tree,int len){
	if(!tree)
	return;
	static int a[20]; //定义静态数组a,保存每个叶子的编码,数组长度至少是树深度减一
	int i;
	if(!tree->left && !tree->right){
		printf(" %d  的哈夫曼编码为:",tree->data);
		for(i = 0; i < len; i++)
		printf("%d",a[i]);
		printf("\n");
	}
	else{//访问到非叶子结点时分别向左右子树递归调用,并把分支上的0、1编码保存到数组a ,的对应元素中,向下深入一层时len值增1 
		a[len] = 0;
		getCoding(tree->left, len + 1);
		a[len] = 1;
		getCoding(tree->right, len + 1);
		
	}
}

//哈夫曼解码
void Decoding(Tree *tree){
	printf("请输入要解码的字符串\n");
	char ch[100];//输入的待解码的字符串 
	gets(ch);
	int i;
	int num[100];//用于保存字符串对应的0 1 编码对应的节点 
	Tree *cur;
	for(i = 0; i < strlen(ch); i++){
		if(ch[i] == '0')
		num[i] = 0;
		else
		num[i] = 1;
	}
	
	if(tree){
		i = 0;
		while(i < strlen(ch)){
			cur = tree;
			while(cur->left && cur->right){
				
				if(num[i] == 0)
				cur = cur->left;
				else
				cur = cur->right;
				i++;
			}
			printf("%d",cur->data);
		}
		
	}
} 

int main(int argc, char *argv[]) {
	int a[4] = {2,6,7,3};
	Tree *tree = create(a,4);
	print(tree);
	printf("\n哈夫曼树的权值为:");
	printf("%d\n",getWeight(tree,0));
	getCoding(tree,0);
	printf("解码时请参照上方编码\n");
	Decoding(tree); 
}

运行结果如下
在这里插入图片描述

  • 10
    点赞
  • 83
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
的构造及编码解码的C语言代码如下: 1. 哈的构造 ```c #include <stdio.h> #include <stdlib.h> typedef struct HuffmanNode { char data; // 数据 int weight; // 权值 struct HuffmanNode *leftChild, *rightChild; // 左孩子和右孩子结点 } HuffmanNode, *HuffmanTree; // 创建新结点 HuffmanNode *createHuffmanNode(char data, int weight) { HuffmanNode *node = (HuffmanNode*) malloc(sizeof(HuffmanNode)); node->data = data; node->weight = weight; node->leftChild = NULL; node->rightChild = NULL; return node; } // 构造哈 HuffmanTree createHuffmanTree(char *data, int *weight, int n) { HuffmanNode **nodes = (HuffmanNode**) malloc(n * sizeof(HuffmanNode*)); for (int i = 0; i < n; i++) { nodes[i] = createHuffmanNode(data[i], weight[i]); } while (n > 1) { int min1 = 0, min2 = 1; // 找到权值最小和次小的两个结点 if (nodes[min1]->weight > nodes[min2]->weight) { int tmp = min1; min1 = min2; min2 = tmp; } for (int i = 2; i < n; i++) { if (nodes[i]->weight < nodes[min1]->weight) { min2 = min1; min1 = i; } else if (nodes[i]->weight < nodes[min2]->weight) { min2 = i; } } HuffmanNode *newNode = createHuffmanNode(0, nodes[min1]->weight + nodes[min2]->weight); newNode->leftChild = nodes[min1]; newNode->rightChild = nodes[min2]; if (min1 < min2) { nodes[min1] = newNode; nodes[min2] = nodes[n - 1]; } else { nodes[min2] = newNode; nodes[min1] = nodes[n - 1]; } n--; } return nodes[0]; } // 测试 int main() { char data[] = {'A', 'B', 'C', 'D', 'E'}; int weight[] = {5, 1, 2, 4, 3}; HuffmanTree tree = createHuffmanTree(data, weight, 5); return 0; } ``` 2. 哈编码 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct HuffmanNode { char data; // 数据 int weight; // 权值 struct HuffmanNode *leftChild, *rightChild; // 左孩子和右孩子结点 } HuffmanNode, *HuffmanTree; typedef struct HuffmanCode { char data; // 数据 char *code; // 编码 } HuffmanCode; // 创建新结点 HuffmanNode *createHuffmanNode(char data, int weight) { HuffmanNode *node = (HuffmanNode*) malloc(sizeof(HuffmanNode)); node->data = data; node->weight = weight; node->leftChild = NULL; node->rightChild = NULL; return node; } // 构造哈 HuffmanTree createHuffmanTree(char *data, int *weight, int n) { HuffmanNode **nodes = (HuffmanNode**) malloc(n * sizeof(HuffmanNode*)); for (int i = 0; i < n; i++) { nodes[i] = createHuffmanNode(data[i], weight[i]); } while (n > 1) { int min1 = 0, min2 = 1; // 找到权值最小和次小的两个结点 if (nodes[min1]->weight > nodes[min2]->weight) { int tmp = min1; min1 = min2; min2 = tmp; } for (int i = 2; i < n; i++) { if (nodes[i]->weight < nodes[min1]->weight) { min2 = min1; min1 = i; } else if (nodes[i]->weight < nodes[min2]->weight) { min2 = i; } } HuffmanNode *newNode = createHuffmanNode(0, nodes[min1]->weight + nodes[min2]->weight); newNode->leftChild = nodes[min1]; newNode->rightChild = nodes[min2]; if (min1 < min2) { nodes[min1] = newNode; nodes[min2] = nodes[n - 1]; } else { nodes[min2] = newNode; nodes[min1] = nodes[n - 1]; } n--; } return nodes[0]; } // 哈编码 void huffmanEncoding(HuffmanTree tree, char *prefix, int depth, HuffmanCode *codes, int *codeIndex) { if (tree->leftChild == NULL && tree->rightChild == NULL) { codes[*codeIndex].data = tree->data; codes[*codeIndex].code = (char*) malloc((depth + 1) * sizeof(char)); strcpy(codes[*codeIndex].code, prefix); (*codeIndex)++; } else { prefix[depth] = '0'; prefix[depth + 1] = '\0'; huffmanEncoding(tree->leftChild, prefix, depth + 1, codes, codeIndex); prefix[depth] = '1'; prefix[depth + 1] = '\0'; huffmanEncoding(tree->rightChild, prefix, depth + 1, codes, codeIndex); } } // 测试 int main() { char data[] = {'A', 'B', 'C', 'D', 'E'}; int weight[] = {5, 1, 2, 4, 3}; HuffmanTree tree = createHuffmanTree(data, weight, 5); char prefix[100]; prefix[0] = '\0'; HuffmanCode codes[5]; int codeIndex = 0; huffmanEncoding(tree, prefix, 0, codes, &codeIndex); for (int i = 0; i < codeIndex; i++) { printf("%c: %s\n", codes[i].data, codes[i].code); } return 0; } ``` 3. 哈解码 ```c #include <stdio.h> #include <stdlib.h> typedef struct HuffmanNode { char data; // 数据 int weight; // 权值 struct HuffmanNode *leftChild, *rightChild; // 左孩子和右孩子结点 } HuffmanNode, *HuffmanTree; // 创建新结点 HuffmanNode *createHuffmanNode(char data, int weight) { HuffmanNode *node = (HuffmanNode*) malloc(sizeof(HuffmanNode)); node->data = data; node->weight = weight; node->leftChild = NULL; node->rightChild = NULL; return node; } // 构造哈 HuffmanTree createHuffmanTree(char *data, int *weight, int n) { HuffmanNode **nodes = (HuffmanNode**) malloc(n * sizeof(HuffmanNode*)); for (int i = 0; i < n; i++) { nodes[i] = createHuffmanNode(data[i], weight[i]); } while (n > 1) { int min1 = 0, min2 = 1; // 找到权值最小和次小的两个结点 if (nodes[min1]->weight > nodes[min2]->weight) { int tmp = min1; min1 = min2; min2 = tmp; } for (int i = 2; i < n; i++) { if (nodes[i]->weight < nodes[min1]->weight) { min2 = min1; min1 = i; } else if (nodes[i]->weight < nodes[min2]->weight) { min2 = i; } } HuffmanNode *newNode = createHuffmanNode(0, nodes[min1]->weight + nodes[min2]->weight); newNode->leftChild = nodes[min1]; newNode->rightChild = nodes[min2]; if (min1 < min2) { nodes[min1] = newNode; nodes[min2] = nodes[n - 1]; } else { nodes[min2] = newNode; nodes[min1] = nodes[n - 1]; } n--; } return nodes[0]; } // 哈解码 void huffmanDecoding(HuffmanTree tree, char *code) { HuffmanNode *p = tree; for (int i = 0; code[i] != '\0'; i++) { if (code[i] == '0') { p = p->leftChild; } else { p = p->rightChild; } if (p->leftChild == NULL && p->rightChild == NULL) { putchar(p->data); p = tree; } } } // 测试 int main() { char data[] = {'A', 'B', 'C', 'D', 'E'}; int weight[] = {5, 1, 2, 4, 3}; HuffmanTree tree = createHuffmanTree(data, weight, 5); char *code = "1011010111001101011110"; huffmanDecoding(tree, code); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值