#include<iostream>
#include<string>
#include<vector>
#include<fstream>
using namespace std;
//定义字符以及权值
struct binaChar{
char value;
int width;
};
//定义储存哈夫曼树节点
struct node {
char value;
int width;
struct node* rchild;
struct node* lchild;
};
//统计字符,赋予权值
void getCharArray(string str,vector<binaChar> & vec) {
for (int i = 0; i <str.size(); i++) {
bool isExist = false;
for (int j = 0; j < vec.size(); j++) {
if (str[i] == vec[j].value) {
vec[j].width++;
isExist = true;
}
}
if (!isExist) {
binaChar bc;
bc.value = str[i];
bc.width = 1;
vec.push_back(bc);
}
}
}
//交换三个变量的值
void swap(binaChar& a, binaChar&b) {
binaChar temp = a;
a = b;
b = temp;
}
//快速排序,方便查找较小的两个权值
int quick(int begin, int end, vector<binaChar>& array) {
int i = begin, j = end;
binaChar pivot = array[begin];
while (i < j) {
while (array[j].width >= pivot.width && j > i) j--;
while (array[i].width <= pivot.width && j > i) i++;
swap(array[j], array[i]);
}
array[begin]= array[i];
array[i]=pivot;
return i;
}
void quickSort(int begin, int end, vector<binaChar>& array) {
if (begin < end) {
int mid =quick(begin, end, array);
quickSort(begin, mid - 1, array);
quickSort(mid + 1, end, array);
}
}
//生成哈夫曼树
void getHuffmanTree(vector<binaChar> bc, struct node*& head) {
vector<node*> tree;
for (int i = 0; i < bc.size(); i++) {
node* n = new node();
n->value = bc[i].value;
n->width = bc[i].width;
n->lchild = n->rchild = NULL;
tree.push_back(n);
}
while (tree.size() > 1) {
int min1 = 0, min2 = 1;//经过排序,已经确定0,1位置的字符权值最小。
node* p = new node();
p->value =NULL;
p->width = tree[min1]->width+tree[min2]->width;
p->lchild = tree[min1];
p->rchild = tree[min2];
tree.erase(tree.begin());//移除已经合并的节点:0,1
tree.erase(tree.begin());
//在指定位置插入新节点
bool isInsert = false;
for (int i = 0; i <tree.size(); i++) {
if (p->width<tree[i]->width) {
tree.insert(tree.begin()+i, p);
isInsert = true;
break;
}
}
//如果新节点权值最大,保证节点被插在最后
if (!isInsert) tree.push_back(p);//
}
head=tree[0];//返回构造完成的树
}
void getString(string& text) {
ifstream infile;
infile.open("D:\\data\\infile\\text.txt", ios::out | ios::in);
if (!infile) {
cout << "待加密文件读取失败!" << endl;
return;
}
getline(infile, text, '\n');
cout<<"字符串写入成功!"<<endl;
infile.close();
}
void Tran(node* root,string str, string& code,char ch) {
if (root == NULL) return;
Tran(root->lchild, str + '0',code,ch);
Tran(root->rchild, str + '1',code,ch);
if (root->value== ch) {
code = str;
return;
}
}
//加密
void getCodeFile(struct node* root, vector<binaChar> bc) {
ifstream infile;
infile.open("D:\\data\\infile\\text.txt", ios::out | ios::in);
if (!infile) {
cout << "待加密文件读取失败!" << endl;
return;
}
string text;
getline(infile,text,'\n');
infile.close();
ofstream outfile;
outfile.open("D:\\data\\infile\\coding.txt", ios::out | ios::in);
if (!outfile) {
cout << "加密文件读取失败!" << endl;
return;
}
for (int i = 0; i < text.size(); i++) {
node* p = root;
string str,temp;
Tran(p,temp, str, text[i]);
outfile <<str;
}
cout << "加密文件写入成功!" << endl;
outfile.close();
}
//解密
char reTran(node* root,string str,int &i) {
while (true) {
if (str[i] == '0') root=root->lchild;
if (str[i] == '1') root=root->rchild;
if (root->value != NULL) return root->value;
i++;
}
}
void decodingFile(struct node* root) {
ifstream infile;
infile.open("D:\\data\\infile\\coding.txt", ios::out | ios::in);
if (!infile) {
cout << "加密文件写入失败!" << endl;
return;
}
string str;
infile >> str;
infile.close();
ofstream outfile;
outfile.open("D:\\data\\infile\\decoding.txt", ios::out | ios::in);
if (!outfile) {
cout<<"解密文件读取失败!"<<endl;
return;
}
for (int i = 0; i < str.size(); i++) {
node* p =root;
char ch=reTran(root, str, i);
outfile <<ch;
}
cout << "解密文件写入成功!" << endl;
outfile.close();
}
int main()
{
string str;
getString(str);
node* head=new node();
vector<binaChar> vec;
getCharArray(str, vec);
quickSort(0, vec.size()-1, vec);
getHuffmanTree(vec,head);
getCodeFile(head,vec);
decodingFile(head);
}
哈夫曼编码能实现文件的压缩,但是由于没有将01串转比特流写入,实际上得到的文件占据更大的空间。所以,涉及到的文件均是为了方便查看。