【数据结构】哈夫曼编码树

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

typedef int Elemtype;
typedef int Status;
//赫夫曼树结点定义
typedef struct HuffmanNode {
	Elemtype weight;  //用来记录结点的权重
	Elemtype id;	  //用来唯一标识结点
	struct HuffmanNode *lchild;
	struct HuffmanNode *rchild;
}*HuffmanTree;

//构建一颗赫夫曼树//
HuffmanTree CreateHuffmanTree(int a[],int n) {
	//返回指向根结点的指针
	//数组a代表每个结点的权重,n代表叶子结点个数
	int i, j;
	HuffmanTree *temp, T;
	//动态分配n个结点的内存空间,temp为指向这些地址空间的头指针
	temp = (HuffmanTree *)malloc(n * sizeof(HuffmanNode));
	//将数组a中的权值分配给每个结点
	for (i = 0; i < n; i++) {
		temp[i] = (HuffmanTree)malloc(sizeof(HuffmanNode));
		temp[i]->weight = a[i];
		temp[i]->id = i;
		temp[i]->lchild = temp[i]->rchild = NULL;
	}
	//构建哈夫曼树
	for (i = 0; i < n - 1; i++) {
		//构建哈夫曼树需要n-1次合并
		int little1 = -1, little2;//前者存放最小的数的下标,后者存放次小的
		for (j = 0; j < n; j++) {
			if (temp[j] != NULL && little1 == -1) {
				little1 = j;
				continue;
			}
			else if (temp[j] != NULL) {
				little2 = j;
				break;//找到了就可以跳出
			}
		}
		//将权值最小的两个数给little1,2
		for (j = little2; j < n; j++) {
			if (temp[j] != NULL) {
				if (temp[j]->weight < temp[little1]->weight) {
					little2 = little1;
					little1 = j; //将次小的给2,自己留更小的一个
				}
				else if (temp[j]->weight < temp[little2]->weight) {
					little2 = j;
				}
			}
		}
		//构造结点
		T = (HuffmanTree)malloc(sizeof(HuffmanNode));
		T->weight = temp[little1]->weight + temp[little2]->weight;//权值为两结点相加
		T->lchild = temp[little1];
		T->rchild = temp[little2];

		temp[little1] = T;   //将构造的结点插入队列中
		temp[little2] = NULL;//删去另外的两个结点
	}
	return T;
}

//用广义表的形式打印这棵树//
void printHuffmanTree(HuffmanTree T) {
	if (T) {
		printf("%d", T->weight);
		if (T->lchild != NULL || T->rchild != NULL) {
			//如果不是叶子结点则执行,如果是的话直接跳出
			//有一个小森林就会有一对括号,即执行这一步
			printf("(");
			printHuffmanTree(T->lchild); //先打印左子树
			printf(",");				 //左右子树中用逗号隔开	
			printHuffmanTree(T->rchild); //再打印右子树
			printf(")");
		}
	}
}

//递归进行赫夫曼编码//
void HuffmanCode(HuffmanTree T, int depth,char str[]) {
	static int code[100];//每次递归值都不会改变,但是一棵树遍历左右子树是值是会变的
	static int i = 0;
	if (T) {
		if (T->lchild == NULL && T->rchild == NULL) {
			//如果该结点是叶子结点的话
			printf("%c的哈夫曼编码为:",str[T->id]);
			i++;
			for (int i = 0; i < depth; i++) {
				printf("%d", code[i]);
			}
			printf("\n");
		}
		else {
			//如果不是叶子结点就进行数值写入
			//左子树写0,右子树写1,根结点写0
			code[depth] = 0;
			HuffmanCode(T->lchild, depth + 1,str);
			code[depth] = 1;  //此时同样深度的code发生了改变
			HuffmanCode(T->rchild, depth + 1,str);
		}
	}
}


//赫夫曼解码//
void HuffmanDecode(HuffmanTree T, char ch[], char str[]) {
	//ch为要解码的01串,str为解码后的字符串
	int i, num[1000];//num用来存放01码
	HuffmanTree temp = NULL;
	//进行存放01码
	for (i = 0; i < strlen(ch); i++) {
		if (ch[i] == 48)
			num[i] = 0;
		else if (ch[i] == 49)
			num[i] = 1;
	}
	//进行解码
	if(T) {
		i = 0;//用来记录01串长度
		while (i < strlen(ch)) {
			//当还没有解码完的时候
			temp = T;
			while (temp->lchild != NULL && temp->rchild != NULL) {
				//当不是叶子结点的时候都要继续
				if (num[i] == 0) {
					temp = temp->lchild;//如果是0就走左边
				}
				else {
					temp = temp->rchild;//如果是1就走右边
				}
				i++;
			}
			//退出的时候就找到了叶子结点,由temp指向
			printf("%c", str[temp->id]);//输出对应的字符
		}
	}
}

int main() {
	int a[53];
	int n = 53;
	char ch[1000];//用来接收01码
	char str[53];//用来存放字母
	for (int i = 65; i <= 90; i++) {
		//大写字母从A-Z
		str[i - 65] = i;
	}
	str[26] = 32;  //空格的ASCII码
	for (int i = 97; i <= 122; i++) {
		//小写字母从a-z
		str[26 + i - 96] = i;
	}
	for (int i = 0; i < 53; i++) {
		//权重值从1-53
		a[i] = i + 1;
	}
	HuffmanTree T;
	T = (HuffmanTree)malloc(sizeof(HuffmanNode));
	T = CreateHuffmanTree(a, n);
	printf("(");
	printHuffmanTree(T);
	printf(")\n");
	HuffmanCode(T, 0,str);
	printf("请输入您要解码的01值:");
	scanf("%s",ch);
	printf("解码的结果是:\n");
	HuffmanDecode(T, ch, str);
	return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值