哈夫曼编码和译码c++数组实现

做软工项目,组长说要把url地址加密,于是想到了哈夫曼编码。c++写了个初始模板,后续改改。
本代码针对是是只包含字母和数字的字符串的编码和译码,可以改动一下变成通用。

#include<bits/stdc++.h>


using namespace std;
const int N = 1e5+9;
struct node
{
	int w;//结点权值 
	int p,lson,rson;//双亲,左孩子,右孩子下标 
}Ht[N]; 
struct code
{
	char ch;
	string code;
}Htcode[N];
string allcode;
struct node2
{
	int w,idx;
	bool operator<(const node2 &t) const
	{
		return w>t.w;
	}
};
char url[N],str[N];
int cnt[N];
bool st[N];
//创建哈夫曼树 
void createHuffmanTree(int n)
{
	int m =2*n - 1;
	//开一个小根堆 
	priority_queue<node2> heap;
	for(int i=1; i<=n; i++)
	{
		heap.push({cnt[str[i]-'0'],i});
	}
	//初始化权值 
	for(int i=1; i<=m; ++i)
	{
		if(i<=n) Ht[i]={ cnt[str[i]-'0'], 0,0,0};
		else Ht[i]={0,0,0,0};
	}
	for(int i=n+1; i<=m; i++)
	{
		auto min_node=heap.top();
		heap.pop();
		auto min2_node=heap.top();
		heap.pop();
		Ht[min_node.idx].p=i, Ht[min2_node.idx].p=i;
		Ht[i].lson=min_node.idx, Ht[i].rson = min2_node.idx;
		Ht[i].w = min_node.w + min2_node.w;
		//新产生的结点放入小根堆当中 
		heap.push({Ht[i].w, i});
	} 
}
//哈夫曼树建立完毕,从 n 个叶子结点到根,逆向求每个叶子结点对应的哈夫曼编码
void  enCode(int n)
{
	if(n==1)
	{
		Htcode[1]={ str[1],"0"};
		return ;
	}
	//求n个叶子节点对应的哈夫曼编码
	for(int i=1; i<=n; ++i)
	{
		string tmp_code=""; 
		for(int j=i, p=Ht[j].p; p!=0; j=p,p=Ht[p].p)
		{
			if(Ht[p].lson==j) tmp_code+='0';
			else tmp_code+='1';		
		}
		reverse(tmp_code.begin(), tmp_code.end());
		Htcode[i]={ str[i],tmp_code };
	} 
} 
string getAllCode(int n)
{
	string tmp_code="";
	int len=strlen(url+1);
	for(int i=1; i<=len; i++)
	{
		for(int j=1; j<=n; j++)
		{
			if(Htcode[j].ch==url[i])
			{
				tmp_code+=Htcode[j].code;
				break;
			}
		}
	}
	return tmp_code;
}
//将01串译码 
string deCode(string tmp_code, int n)
{
	string mydecode="";
	if(n==1) 
	{
		for(int i=0; i<tmp_code.size(); i++) mydecode+=Htcode[1].ch;
		return mydecode; 
	}
	int tmp_idx=2*n-1; 
	for(int i=0; i<tmp_code.size(); ++i)
	{
	
		if(tmp_code[i]=='0') tmp_idx=Ht[tmp_idx].lson;
		else tmp_idx=Ht[tmp_idx].rson;
		if(Ht[tmp_idx].lson==0 && Ht[tmp_idx].rson==0)
		{
			mydecode+=str[tmp_idx];
			tmp_idx=2*n-1;
		}
	}
	return mydecode;
}
int main()
{
	printf("情输入url: ");
	cin>>url+1;
	int len=strlen(url+1);
	//每个数字出现的频数作为权值 
	for(int i=1; i<=len; i++) cnt[url[i]-'0']++;
	int len2=0;
	for(int i=1; i<=len; i++)
	{
		if(!st[url[i]-'0']) 
		{
			str[++len2]=url[i];
			st[url[i]-'0']=true;
		}
	}
	str[len2+1]='\0';
//	if(len2==1) 
//	{
//			cout<<"哈夫曼编码: "<<0<<endl;
//			cout<<"译码之后: "<<url+1<<endl; 
//			return 0;
//	}
	//cout<<str+1<<endl;
	//构建哈夫曼树
	createHuffmanTree(len2); 
	enCode(len2);
	string myencode=getAllCode(len2);
	cout<<"哈夫曼编码: "<<myencode<<endl;
	string myDeCode=deCode(myencode,len2);
	cout<<"哈夫曼译码: "<<myDeCode<<endl; 
	return 0;
} 
上一篇:LeetCode 2018. 判断单词是否能放入填字游戏内(模拟)


下一篇:JBoss中间件漏洞