做软工项目,组长说要把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;
}