哈夫曼编码C++实现

#include<iostream>
#include<iomanip>
using namespace std;
#pragma warning (disable: 4996)

类型定义

typedef struct {//哈夫曼树
	int weight;//权值
	int lch, rch, parent;//左右孩子,父结点
}HTNode,*HuffmanTree;

二级指针建立一个哈夫曼编码表

typedef char** HuffmanCode;
void CreatHuffmanTree(HuffmanTree& HT, int n) {
    //构造哈夫曼树
	if (n <= 1)return;
	int m = 2 * n - 1;//数组2n-1个元素
	HT = new HTNode[m + 1];//0号不用
	for (int i = 1; i <= m; i++) {
		//将2n-1个元素的lch,rch,parent设置为0
		HT[i].lch = 0; HT[i].rch = 0; HT[i].parent = 0;
	}
	for (int i = 1; i <= n; i++)
		cin >> HT[i].weight;//输入前n个元素的weight
	//初始化结束
	//建立哈夫曼树
	for (int i = n + 1; i <= m; i++) {
		//合并产生n-1个结点,构造哈夫曼树
		int s1, s2;
		Select(HT, i - 1, s1, s2);//找到i以前的最小的俩下标,用s1,s2返回
		HT[s1].parent = i;
		HT[s2].parent = i;
		//parent的初值为0,如果parent不为0,则说明已经构造成树了,可以用来Select函数判定
		HT[i].lch = s1;
		HT[i].rch = s2;
		HT[i].weight = HT[s1].weight + HT[s2].weight;
	}

}

Select函数是哈夫曼算法的重要过程,找到未成树的叶子结点的两个最小权值结点,并用s1,s2返回下标

void Select(HuffmanTree HT, int n, int& s1, int& s2) {
	s1 = s2 = 0;
	for (int i = 1; i <= n; i++) {
		if (HT[i].parent == 0) {
			s1 = i;
			break;
		}

	}//找一个未归树的结点开始判断

	for (int i = 1; i <= n; i++) {
		if (HT[i].parent == 0 && HT[i].weight < HT[s1].weight)
			s1 = i;
	}
	for (int i = 1; i <= n; i++) {
		if (HT[i].parent == 0 && i != s1) {//排除掉s1
			s2 = i;
			break;
		}
	}//找一个未归树的结点开始判断
	for (int i = 1; i <= n; i++) {
		if (HT[i].parent == 0 && HT[i].weight < HT[s2].weight && i != s1)//排除掉s1
			s2 = i;
	}
}

构造哈夫曼编码

从叶子一步一步向上回溯,找到自己的parent,然后得到自己是左还是右孩子

void CreateHuffmanCode(HuffmanTree&HT,HuffmanCode&HC,int n) {
	//从叶子到根逆向求每个字符的哈夫曼编码,储存在编码表HC中
	HC = new char* [n + 1];//分配n个字符编码的头指针矢量,第0个不放
	char* cd = new char[n];
	cd[n - 1] = '\0';
	for (int i = 1; i <= n; i++) {//i为初始为叶子,后面为当前回溯结
		int start = n - 1, c = i, f = HT[i].parent;
		while (f != 0) {
			--start;
			if (HT[f].lch == c)
				cd[start] = '0';//左0
			else cd[start] = '1';//右1
			c = f; f = HT[f].parent;
			//向上回溯一级
		}
		HC[i] = new char[n - start];//分配该编码所需要的空间
		strcpy(HC[i], &cd[start]);//从start开始复制
	}
	delete cd;
}

打印哈夫曼树表,setw是#include<iomanip>里面的,用来方便输出

void PrintHuffman(HuffmanTree HT, int n) {
	cout << "index weight parents lchild rchild" << endl;
	cout << left;
	for (int i = 1; i <= 2 * n - 1; i++) {
		cout << setw(6) << i << " ";
		cout << setw(6) << HT[i].weight << " ";
		cout << setw(6) << HT[i].parent << " ";
		cout << setw(6) << HT[i].lch << " ";
		cout << setw(6) << HT[i].rch << " " << endl;
	}
}

打印编码表

void PrintHuffmancode(HuffmanCode&HC,int n) {
	cout << "每个叶子的哈夫曼编码为" << endl;
	for (int i = 1; i <= n; i++) {
		cout << HC[i] << endl;
	}
}

测试函数test01

void test01() {
	HuffmanTree HT;
	HuffmanCode HC;
	int n=0;
	cin >> n;

	CreatHuffmanTree(HT, n);
	PrintHuffman(HT, n);
	CreateHuffmanCode(HT, HC, n);
	PrintHuffmancode(HC, n);

	//7 40 30 15 5 4 3 3

}

 结果

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值