哈夫曼编码(C++)实现

此为数据结构哈夫曼编码实验,因供参考,源地址:https://download.csdn.net/download/weixin_43314490/12094176

IDE为VS2019



#include<iostream>
#include<string>
#include<iomanip>
using namespace std;
struct HNode
{
	int weight;
	int parent;
	int LChild;
	int RChild;
};
struct HCode
{
	char data;
	char code[1000];
};


class Huffman  //哈夫曼类
{
private:
	HNode* HTree;
	HCode* HCodeTable;
	int N;
public:
	Huffman();//构造函数
	void Init(char* s);//初始化函数
	void CreateHTree(int a[], int n);//创建赫夫曼树
	void CreateTable(char b[], int n);//创建编码表
	void Encoding(char* s, char* d);//加密函数
	void Decoding(char* s, char* d);//解密函数
	void Select(int& x, int& y, int start, int end);//选择权值最小和次小的两个节点
	void Reverse(char* s);//反转字符串
	void Ratio(char* s, char* d);//计算压缩比
	~Huffman();//析构函数
};

Huffman::Huffman()
{
	HTree = NULL;
	HCodeTable = NULL;
	N = 0;
}

void Huffman::Init(char* s)//初始化
{
	int a[1000] = { 0 };//储存每个字符的个数
	char b[1000] = { 0 };//储存字符的种类
	int length = strlen(s);//统计字符串长度
	if (length > 1000)//如果字符长度大于10000则不再执行本函数
	{
		throw length;    //异常处理 throw后面的语句将不在执行
	}
	int j = 0;
	for (int i = 0; i < length; i++)//计算每个不同字符的权值
	{
		char c = s[i];//取字符串中的每个字符
		for (j = 0; j < N; j++)//判断字符是否重复
		{
			if (c == b[j])
			{
				a[j]++;
				break;
			}
		}
		if (j == N)//计算权值
		{
			a[j] = 1;
			b[j] = s[i];
			N++;
		}
	}
	CreateHTree(a, N);//创建哈夫曼树
	CreateTable(b, N);//创建编码表
}


void Huffman::Select(int& x, int& y, int start, int end)//寻找权重最小的两个数的位置
{
	x = 0, y = 0;
	while (HTree[x].parent != -1)
	{
		x++;
	}
	for (int i = 1; i < end; i++)
	{
		if (HTree[i].parent != -1)
		{
			continue;//如果是之前找出的最小值,跳出本次循环
		}
		if (HTree[i].weight < HTree[x].weight)
		{
			x = i;
		}
	}
	HTree[x].parent = -2018210071;//防止重复
	while (HTree[y].parent != -1)
	{
		y++;
	}
	for (int j = 1; j < end; j++)
	{
		if (HTree[j].parent != -1)
		{
			continue;
		}
		if (HTree[j].weight < HTree[y].weight)
		{
			y = j;
		}
	}
}


void Huffman::CreateHTree(int a[], int n)
{
	HTree = new HNode[2 * n - 1];//申请2n-1个结点内存空间
	for (int i = 0; i < n; i++)
	{
		HTree[i].weight = a[i];//输入权值
		HTree[i].LChild = -1;//将哈夫曼树的每个结点数据初始化为1
		HTree[i].RChild = -1;
		HTree[i].parent = -1;
	}
	int x, y;//数据中最小的两个数
	for (int i = n; i < 2 * n - 1; i++)
	{
		Select(x, y, 0, i);//获取数据中最小的两个数
		HTree[x].parent = HTree[y].parent = i;//生成哈夫曼树的每个结点
		HTree[i].weight = HTree[x].weight + HTree[y].weight;
		HTree[i].LChild = x;
		HTree[i].RChild = y;
		HTree[i].parent = -1;
	}
}


void Huffman::CreateTable(char b[], int n)//建立编码表
{
	HCodeTable = new HCode[n];//申请输出编码表所需的空间
	for (int i = 0; i < n; i++)//建立编码表
	{
		HCodeTable[i].data = b[i];//将每个不同的字符赋值到编码表的数据域
		int ChildNum = i;
		int parent = HTree[i].parent;
		int k = 0;
		while (parent != -1)//为每一个不同的字符编码(此循环后获得的编码为所需编码的倒序)
		{
			if (ChildNum == HTree[parent].LChild)//奇数为左孩子,偶数为右孩子
				HCodeTable[i].code[k] = '0';
			else
				HCodeTable[i].code[k] = '1';
			k++;
			ChildNum = parent;
			parent = HTree[ChildNum].parent;
		}
		HCodeTable[i].code[k] = '\0';
		Reverse(HCodeTable[i].code);//将编码倒序,生成所需的编码
	}
	for (int i = 0; i < N; i++)//输出编码表
		cout << HCodeTable[i].data << "的编码为:" << HCodeTable[i].code << endl;
}


void Huffman::Reverse(char* s)//将编码倒序
{
	int length = strlen(s);
	char temp[1000];
	for (int i = 0; i < length; i++)
		temp[i] = s[length - i - 1];
	for (int i = 0; i < length; i++)
		s[i] = temp[i];
}


void Huffman::Encoding(char* s, char* d)//根据编码表为字符串编码
{
	Init(s);//将字符串初始化
	int length = strlen(s);
	int k = 0;
	for (int i = 0; i < length; i++)
	{
		for (int j = 0; j < N; j++)
		{
			if (s[i] == HCodeTable[j].data)
			{
				int p = 0;
				while (HCodeTable[j].code[p] != '\0')
				{
					d[k] = HCodeTable[j].code[p];//按照编码表对字符串中的每个字符进行编码
					k++;
					p++;
				}
			}
		}
	}
	d[k] = '\0';//字符串编码结束,方便调用时确定结束条件
}


void Huffman::Decoding(char* s, char* d)//译码
{
	while (*s != '\0')
	{
		int parent = 2 * N - 2;
		while (HTree[parent].LChild != -1)
		{
			if (*s == '0')
				parent = HTree[parent].LChild;
			else
				parent = HTree[parent].RChild;
			s++;
		}
		*d = HCodeTable[parent].data;//把编码后的字符串数组中的每个数据按照编码表反译
		d++;
	}
	*d = '\0';//译码结束,方便调用时确定结束条件
}


void Huffman::Ratio(char* s, char* d)//计算压缩比
{
	int n1 = strlen(s);//计算字符串编码前的长度
	int n2 = strlen(d);//计算字符串编码后的长度,如果不能整除则向上取整
	if (n2 % 8 != 0)
	{
		n2 = n2 / 8 + 1;
	}
	else
	{
		n2 = n2 / 8;
	}
	cout << "编码前长度为:" << n1 << endl;
	cout << "编码后长度为:" << n2 << endl;
	cout << "压缩比为:" << double(100 * n2 / n1) << "%" << endl;//输出压缩比
}

Huffman::~Huffman()//析构函数 释放内存
{
	delete[]HTree;
	delete[]HCodeTable;
}

int  main(void)
{
pos:
	Huffman H1;
	Huffman H2;
	char s[1000] = { '\0' }, d[1000] = { '\0' }, q[1000] = { '\0' }, dd[1000] = { '\0' }, qq[1000] = { '\0' };
	cout << "********************************************************************************" << endl;
	cout << "                        欢迎执行哈夫曼编/译码器程序" << endl;
	cout << "********************************************************************************" << endl;
	char Choice;
	cout << "                        *         菜单         *" << endl;
	cout << "                        ************************" << endl;
	cout << "                        *   A. 代码功能测试    *" << endl;
	cout << "                        *   B. 进入交互界面    *" << endl;
	cout << "                        ************************" << endl;
	cout << "请选择需要进行的操作:";
	cin >> Choice;
	cin.ignore();
	if (Choice == 'A')
	{
		char text[] = "this is an example of a huffman tree.";
		char* t = text;
		cout << "测试字符串为:" << t << endl;
		cout << "********************************************************************************" << endl;
		H1.Encoding(t, dd);
		H1.Decoding(dd, qq);
		cout << "********************************************************************************" << endl;
		cout << "编码结果为:" << dd << endl;
		cout << "********************************************************************************" << endl;
		cout << "解码结果为:" << qq << endl;
		cout << "********************************************************************************" << endl;
		H1.Ratio(t, dd);
		cout << "********************************************************************************"<<endl;
		cout << endl;
	}
	else
	{
		try
		{
			cout << "********************************************************************************" << endl;
			cout << "下面进入交互界面:" << endl << endl;
			cout << "********************************************************************************"<<endl;
			cout << "请输入字符串:" << endl;
			cin.getline(s, 1000, '\n');
			H2.Encoding(s, d);
			H2.Decoding(d, q);
			cout << "编码结果为:" << d << endl;
			cout << "********************************************************************************" << endl;
			cout << "解码结果为:" << q << endl;
			cout << "********************************************************************************" << endl;
			H2.Ratio(s, d);
			cout << "********************************************************************************" << endl;
		}
		catch (int m)
		{
			cout << "字符串长度为" << m << ">1000 overflow" << endl;//异常处理,内存泄漏
		}
	}
	char YN;
	cout << "是否要退出(Y or N)?" << endl;
	cin >> YN;
	cin.ignore();
	if (YN != 'Y')
	{
		goto pos;
	}
	system("pause");
}

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
哈夫曼编码是一种可变字长编码方式,它可以将不同长度的字符编码为等长的二进制码,从而实现数据的压缩。下面是C++实现哈夫曼编码的代码: #include <iostream> #include <queue> #include <vector> #include <string> #include <map> using namespace std; struct Node { char ch; int freq; Node* left; Node* right; Node(char c, int f) : ch(c), freq(f), left(nullptr), right(nullptr) {} }; struct cmp { bool operator()(Node* a, Node* b) { return a->freq > b->freq; } }; void encode(Node* root, string str, map<char, string>& huffmanCode) { if (!root) { return; } if (!root->left && !root->right) { huffmanCode[root->ch] = str; } encode(root->left, str + "0", huffmanCode); encode(root->right, str + "1", huffmanCode); } void decode(Node* root, int& index, string str) { if (!root) { return; } if (!root->left && !root->right) { cout << root->ch; return; } index++; if (str[index] == '0') { decode(root->left, index, str); } else { decode(root->right, index, str); } } void buildHuffmanTree(string text) { map<char, int> freq; for (char c : text) { freq[c]++; } priority_queue<Node*, vector<Node*>, cmp> pq; for (auto p : freq) { pq.push(new Node(p.first, p.second)); } while (pq.size() > 1) { Node* left = pq.top(); pq.pop(); Node* right = pq.top(); pq.pop(); Node* parent = new Node('$', left->freq + right->freq); parent->left = left; parent->right = right; pq.push(parent); } Node* root = pq.top(); map<char, string> huffmanCode; encode(root, "", huffmanCode); cout << "Huffman Codes are:\n" << endl; for (auto p : huffmanCode) { cout << p.first << " : " << p.second << endl; } cout << "\nOriginal string was:\n" << text << endl; string encodedString = ""; for (char c : text) { encodedString += huffmanCode[c]; } cout << "\nEncoded string is:\n" << encodedString << endl; int index = -1; cout << "\nDecoded string is:\n"; while (index < (int)encodedString.size() - 2) { decode(root, index, encodedString); } }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值