哈夫曼编码

哈夫曼编码(实现加结果)

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

代码:

#include<iostream>
#include <cstring>
using namespace std;

//动态分配数组存储哈夫曼编码
typedef char** HuffmanCode; 

typedef struct Huffman {
	char data;  //代表的值
	int weight;  //节点权值
	int lchild,rchild;
	int parent;
}*HuffmanTree,Huffman;


int* Type(string s,int *a) {  //65-90大写,97-122小写,空格为32
              //分别用于存储26个字母的大小写,还有空格
	for (char m : s) {
		if (m == 32) a[0]++; // " "
		if (m == 44) a[1]++; // ","
		if (m == 46) a[2]++;// "."
		if (m >= 65 && m <= 90) a[m - 62]++;  //大写
		if (m >= 97 && m<=122) a[m - 68]++;//小写
	}
	return a;
}

int m = 0; //HuffmanTree结点个数
int s1, s2;  //此时权值最小的两个结点位置
int *nowread;
/*
	首先,将集合S里面的数组进行一次排序,找到权值最小的两个
	数,然后再设置这两个数的parent结点的数据为parent结点的下标。
	并且设置parent结点的data为两个孩子结点的data之和。然后将已经由
	parent的结点从集合S中移去。
	然后,继续重复上面步骤,继续对集合中剩下的元素进行排序。
	重复以上操作,直到最后传进来的值为2的时候。
*/
void Select(HuffmanTree &HT, int n, int &m1, int &m2) {
	//排序,找出现在数组中权值最小的两个数
	int min = 10000,secmin = 10000;
	for (int i = 1; i <= n ; i++) {
		if (HT[i].parent == 0 && HT[i].weight < min) {
			min = HT[i].weight;
			m1 = i;
		}
	}
	for (int i = 1; i <= n; i++)
	{
		if (HT[i].parent == 0 && (HT[i].weight < secmin) && (i != s1))
		{
			secmin = HT[i].weight;
			s2 = i;
		}
	}
	
}

void Create_HuffmanTree(HuffmanTree &HT,int n,int (&a)[55]) { 
	//构造哈夫曼树
	if (n <= 1) return;  //只有一个结点,不需要编码
	m = 2 * n - 1; //统计结点个数
	HT = new Huffman[m + 1]; 
	//nowread = new int[m + 1];
	char b = 'A', c = 'a';
	for (int i = 1; i <= m; i++) { //初始化
		if (i == 1) HT[i].data = ' '; // " "
		if (i == 2) HT[i].data = ','; // ","
		if (i == 3) HT[i].data = '.';// "."
		if (i >=4 && i<=29) HT[i].data = b++;  //大写
		if (i >=30 && i<=55) HT[i].data = c++;//小写
		
		HT[i].parent = 0;
		HT[i].lchild = 0;
		HT[i].rchild = 0;
	}
	for (int i = 1; i <= n; i++) {
		HT[i].weight = a[i-1];
	}
	/*-----------------开始创建哈弗曼树----------------------*/
	for (int i = n + 1; i <= m; i++) {  //由于从1出发,所以是从n+1开始反向遍历回1
		//通过n-1次选择、删除、合并创建哈弗曼树
		Select(HT, i - 1, s1, s2);
		//在HT[k](1<=k<=i-1)中选择两个其双亲域为0且权值最小的结点,并返回它们在HT中的序号s1和s2
		HT[s1].parent = i;
		HT[s2].parent = i;
		//得到新的结点i,从森林中删除s1,s2,将双亲结点s1和s2的双亲域由0改成1
		HT[i].lchild = s1;
		HT[i].rchild = s2;
		HT[i].weight = HT[s1].weight + HT[s2].weight;
	}
	/*
	cout << "输出HT中的权值:" << endl;
	for (int i = 1; i <= m; i++) {
		cout <<i<<":\t"<< HT[i].weight<<"\t"<<HT[i].parent<< endl;
	}
	cout << endl;
	int sum = 0;
	for (int i = n+1; i <= m; i++) {
		sum += HT[i].weight;
	}
	cout << "和为:" << sum<<endl;
	*/
}

char *cd;
int start,c,f;
void CreateHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n) {
	//从根节点到根逆向求每一个字符的哈夫曼编码,存储在编码表HC中
	HC = new char* [n + 1];
	cd = new char[n];  //创建一个临时的编码表
	cd[n - 1] = '\0'; //编码结束符
	for (int i = 1; i <= n; i++) {
		start = n - 1;  //由于哈夫曼解码的时候是从叶结点出发的,所以输出时倒序的
		                //所以在译码的时候也是需要倒序
		c = i;
		f = HT[i].parent;
		while (f != 0) { //当父节点不为0时
			--start;
			if (HT[f].lchild == c) cd[start] = '0'; //当不是根结点的时候,就对左孩子进行0编码
			else cd[start] = '1';  //右孩子的时候,1编码
			c = f;  
			f = HT[f].parent;
		}
		HC[i] = new char[n - start];  //动态分配每一个结点编码所需要的空间大小
		//memcpy(HC[i],&cd[start],sizeof(cd[start]));
		int k = n - 1;
		for (int j = n - start - 1; j >= 0 ; j--) {
			
			HC[i][j] = cd[k];
			//cout << HC[i][j];
			k--;
		}
		//cout << "\t";
	}
	delete cd;
}

//编码
string Code(string s,HuffmanCode HC) {
	string code;
	int i = 0;
	for (char m : s) {
		if (m == 32) {
			i = 0;
			while (HC[1][i] != '\0') {
				code.push_back(HC[1][i]);
				i++;
			}
		}
		if (m == 44) {
			i = 0;
			while (HC[2][i] != '\0') {
				code.push_back(HC[2][i]);
				i++;
			}
		}
		if (m == 46) {
			i = 0;
			while (HC[3][i] != '\0') {
				code.push_back(HC[3][i]);
				i++;
			}
		}
		if (m >= 65 && m <= 90) {
			i = 0;
			while (HC[m - 61][i] != '\0') {
				code.push_back(HC[m-61][i]);
				i++;
			}
		}
		if (m >= 97 && m <= 122) {
			i = 0;
			while (HC[m - 67][i] != '\0') {
				code.push_back(HC[m-67][i]);
				i++;
			}
		}
	}
	return code;
}

//译码
void getCode(string code,HuffmanTree HT ){
	int next = 109;
	HuffmanTree p = HT;
	for (char m : code) {
		
		if (m == '0' && p[next].lchild != 0) {
			
				next = p[next].lchild;
		}
		if (m == '1' && p[next].rchild != 0) {
			
			next = p[next].rchild;
		}
		if (p[next].lchild == 0 && p[next].rchild == 0)
		{
			cout << p[next].data;
			next = 109;
		}
	}
}
int main() {
	string s = "The Chinese official said he viewed the Trump Presidency not as an aberration but as the product of a failing political system.\
This jibes with other accounts. The Chinese leadership believes \
that the United States, and Western democracies in general, haven’t risen to the challenge of a globalized economy,\
which necessitates big changes in production patterns,\
as well as major upgrades in education and public infrastructure.\
In Trump and Trumpism, the Chinese see an inevitable backlash to this failure.";
	//string s = " ,.ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
	int a[55] = {0};
	Type(s,a);
	/*
	cout << "输出数组a" << endl;
	for (int i = 0; i < 55; i++) {
		cout <<i<<":\t"<<a[i]<<endl;
	}
	*/
	HuffmanTree HT;
	int n = 55; //会出现的字符的个数
	Create_HuffmanTree(HT, n,a);  //创建HuffmanTree,并且将26个字母的大小写和,.“ ”传入其中
	//cout << s1 << "\t" << s2 << endl;
	HuffmanCode HC;  //创建HuffmanCode
	CreateHuffmanCode(HT, HC, n);
	/* //输出哈夫曼编码表
	int i = 1;
	for (; i <= n; i++) {
		int j = 0;
		while (HC[i][j] != '\0') {
			cout << HC[i][j];
			j++;
		}
		cout << " ";
	}
	*/

	string code = Code(s,HC);
	//cout << endl;

	//编码
	cout << "-----编码-----" << endl;
	for (char m : code) {
		cout << m;
	}
	
	cout << endl;

	//译码
	cout << "------译码-----" << endl;
	getCode(code, HT);
	
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值