根据哈夫曼树求哈夫曼编码长度

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

#define MAXINT 32767

// 哈夫曼树每一个结点的类型
typedef struct  HuffmanTreeNodeType {
	int weight;                     // 权值
	int parent, lchild, rchild;     // 双亲、左孩子、有孩子的位置
} HuffmanTreeNodeType;

// 找最小的根结点和次小的根结点
void MinSubmin(HuffmanTreeNodeType* HuffmanTree, int end, int* MinLocation, int* SubminLocation) {
	int min = MAXINT, submin = MAXINT;
	for (int i = 0; i <= end; i++) {
		if (HuffmanTree[i].weight < min && HuffmanTree[i].parent == 0) {
			submin = min;
			*SubminLocation = *MinLocation;
			min = HuffmanTree[i].weight;
			*MinLocation = i;
		}
		else if (HuffmanTree[i].weight < submin && HuffmanTree[i].parent == 0) {
			submin = HuffmanTree[i].weight;
			*SubminLocation = i;
		}
	}
}

// 打印顺序表
void print(HuffmanTreeNodeType* HuffmanTree, int end) {
	printf("\n索引\t权值\t双亲域\t左孩子域\t右孩子域\n");
	for (int i = 0; i < end; i++) {
		printf("%d\t%d\t%d\t%d\t\t%d\n", i, HuffmanTree[i].weight, HuffmanTree[i].parent, HuffmanTree[i].lchild, HuffmanTree[i].rchild);
	}
}

// 创建哈夫曼树
void CreatHuffmanTree(HuffmanTreeNodeType** HuffmanTree, int n) {
	// 先初始化一个数组,即哈夫曼树的初态
	// 有n个结点,需要n-1次合并,共产生2n-1个结点
	(*HuffmanTree) = (HuffmanTreeNodeType*)malloc(sizeof(HuffmanTreeNodeType) * (2 * n - 1));
	// 每一个结点的四个域均初始化为0
	for (int i = 0; i < 2 * n - 1; i++) {
		(*HuffmanTree)[i].parent = 0;
		(*HuffmanTree)[i].lchild = 0;
		(*HuffmanTree)[i].rchild = 0;
		(*HuffmanTree)[i].weight = 0;
	}
	// 读取n个结点的权值,存放在结点顺序表的前n个位置,索引从0到n-1
	printf("请输入每一个结点的权值: ");
	for (int i = 0; i < n; i++) {
		scanf("%d", &(*HuffmanTree)[i].weight);
	}

	// 打印顺序表的初态
	printf("\n顺序表的初态:\n");
	print((*HuffmanTree), 2 * n - 1);

	int MinLocation, SubminLocation;

	// 在结点顺序表的后面n-1个位置上,每次找两个结点最小值,构成新结点
	for (int i = n; i < 2 * n - 1; i++) {
		MinSubmin((*HuffmanTree), i - 1, &MinLocation, &SubminLocation);
		(*HuffmanTree)[i].lchild = MinLocation;
		(*HuffmanTree)[i].rchild = SubminLocation;
		(*HuffmanTree)[i].weight = (*HuffmanTree)[MinLocation].weight + (*HuffmanTree)[SubminLocation].weight;
		(*HuffmanTree)[MinLocation].parent = i;
		(*HuffmanTree)[SubminLocation].parent = i;
	}
}

// 求每一个叶子结点的哈夫曼编码
void HuffmanCode(HuffmanTreeNodeType* HuffmanTree, char*** HuffmanCodeList, int n) {
	(*HuffmanCodeList) = (char**)malloc(sizeof(char*) * n);
	char* cd = (char*)malloc(sizeof(char) * n);
	//cd[n - 1] = '\0';
	memset(cd, '\0', sizeof(cd));
	for (int i = 0; i < n; i++) {
		int start = n - 1;
		int cur = i;
		int par = HuffmanTree[i].parent;
		while (par != 0) {
			--start;
			if (HuffmanTree[par].lchild == cur)
				cd[start] = '0';
			else
				cd[start] = '1';
			cur = par;
			par = HuffmanTree[cur].parent;
		}
		(*HuffmanCodeList)[i] = (char*)malloc(sizeof(char) * (n - start));
		strcpy((*HuffmanCodeList)[i], &cd[start]);
	}
	free(cd);
}

// 打印哈夫曼编码
void PrintHuffmanCode(HuffmanTreeNodeType* HuffmanTree, char** HuffmanCodeList, int n) {
	printf("各个叶子结点的哈夫曼编码为:\n");
	for (int i = 0; i < n; i++)
		printf("%d: %s\n", HuffmanTree[i].weight, HuffmanCodeList[i]);
}

// 求哈夫曼编码的长度
int GetHuffmanCodeLength(HuffmanTreeNodeType* HuffmanTree, char** HuffmanCodeList, int n) {
	int length = 0;
	for (int i = 0; i < n; i++) {
		length += HuffmanTree[i].weight * strlen(HuffmanCodeList[i]);
	}
	return length;
}

int main(void) {
	// 定义一棵哈夫曼树
	HuffmanTreeNodeType* HuffmanTree;
	// 定义结点个数
	int n;
	// 读入哈夫曼树的结点个数
	printf("请哈夫曼树的结点个数: ");
	scanf("%d", &n);
	// 创建哈夫曼树
	CreatHuffmanTree(&HuffmanTree, n);
	// 打印顺序表的终态
	printf("\n顺序表的终态:\n");
	print(HuffmanTree, 2 * n - 1);
	// 求每一个叶子结点的哈夫曼编码
	// 定义一个字符串数组,每一个字符串对应着一个叶子结点的编码
	char** HuffmanCodeList;
	HuffmanCode(HuffmanTree, &HuffmanCodeList, n);
	// 打印哈夫曼编码
	printf("\n");
	PrintHuffmanCode(HuffmanTree, HuffmanCodeList, n);
	// 求哈夫曼编码的长度
	printf("各个叶子结点的哈夫曼编码的长度:");
	int HuffmanCodeLength = GetHuffmanCodeLength(HuffmanTree, HuffmanCodeList, n);
	printf("%d\n", HuffmanCodeLength);
	return 0;
}

执行结果:

请哈夫曼树的结点个数: 8
请输入每一个结点的权值: 5 29 7 8 14 23 3 11

顺序表的初态:

索引    权值    双亲域  左孩子域        右孩子域
0       5       0       0               0
1       29      0       0               0
2       7       0       0               0
3       8       0       0               0
4       14      0       0               0
5       23      0       0               0
6       3       0       0               0
7       11      0       0               0
8       0       0       0               0
9       0       0       0               0
10      0       0       0               0
11      0       0       0               0
12      0       0       0               0
13      0       0       0               0
14      0       0       0               0

顺序表的终态:

索引    权值    双亲域  左孩子域        右孩子域
0       5       8       0               0
1       29      13      0               0
2       7       9       0               0
3       8       9       0               0
4       14      11      0               0
5       23      12      0               0
6       3       8       0               0
7       11      10      0               0
8       8       10      6               0
9       15      11      2               3
10      19      12      8               7
11      29      13      4               9
12      42      14      10              5
13      58      14      1               11
14      100     0       12              13

各个叶子结点的哈夫曼编码为:
5: 0001
29: 10
7: 1110
8: 1111
14: 110
23: 01
3: 0000
11: 001
各个叶子结点的哈夫曼编码的长度:271
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值