环境是Visual Studio 2017 x64 本地
第一行是防C4996警报妨碍scanf等函数的正常编译使用
=v=还没做的同学可以参考一下
加密代码思路
12source1
逐字符读入文章,记录读入的不同种字符及数量,
分别作为哈夫曼树的结点和权值。
构造哈夫曼树
用根节点遍历哈夫曼树
得到各字符的编码,并输出到12code
再次读入文章,并根据字符将对应编码输出在12encrypt
解密代码思路
读取12code构造一颗哈夫曼树
读入12encrypt边读边遍历,直到遇到叶子结点输出
将结果输出到12source2
加密Encrypt.cpp
#pragma warning(disable:4996)
//#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <string>
#include <cctype>
using namespace std;
#define MaxSize 10000
struct HTnode { //结点符号,权值,父结点,左右子结点
char ch;
int weight;
HTnode *pa;
HTnode *lc, *rc;
};
FILE *in, *out;
HTnode* s[MaxSize];
string code[MaxSize], table;
int n;
//table装读入的不同的字符,code装table字符对应位置的哈夫曼加密编码
//结点的权值也就是出现的数量,n装字符数量,s装所有结点的指针
void InitHTnode(HTnode *&h) {
h = (HTnode *)malloc(sizeof(HTnode));
h->pa = h->lc = h->rc = NULL;
h->ch = h->weight = 0;
}//初始化结点,防止ch越界
void Init() {
n = 0;
int k, p;
string st = "";
in = fopen("12source1.txt", "r+");
if (in == NULL) {
puts("读入失败12source1.txt");
exit(1);
} //对读入输出异常的处理,后面文件流打开都会控制
while (~(k = fgetc(in))) { //逐字符读入
p = st.find((char)k); //查是否有重复
if (p == -1) {
st = st + (char)k;
//无重复,加入table,加入叶子结点
InitHTnode(s[n]);
s[n]->lc = s[n]->rc = s[n]->pa = NULL;
s[n]->ch = (char)k;
s[n]->weight = 1;
n++;
}
else {
s[p]->weight++;
}
}
table = st;
if (n == 1) { //处理只有一种字符的情况
s[1] = s[0];
InitHTnode(s[0]);
s[0]->lc = s[1];
s[1]->pa = s[0];
}
fclose(in); //确认文件流打开,用完就必须关闭
}
void Cal() {
int i, k;
HTnode *mn1, *mn2; //分别装最小最大值
for (k = n; k < n * 2 - 1; k++)
{ //k装父亲结点
mn1 = mn2 = NULL;
for (i = 0; i < k; i++)
if (!s[i]->pa) //找树根,并将权值排序
{
if (!mn1 || s[i]->weight < mn1->weight) {
mn2 = mn1;
mn1 = s[i];
}
else if (!mn2 || s[i]->weight < mn2->weight) {
mn2 = s[i];
}
}
InitHTnode(s[k]); //将最小权值两棵树合并,生成新的树
s[k]->weight = mn1->weight + mn2->weight;
mn1->pa = s[k];
mn2->pa = s[k];
s[k]->lc = mn1;
s[k]->rc = mn2;
}
}
void find(HTnode *h, string s)
{
if (h->lc) find(h->lc, s + "0");
if (h->rc) find(h->rc, s + "1");
if (!h->lc && !h->rc && h->ch > 0 && h->ch < 256) {
code[table.find(h->ch)] = s;
if (isgraph(h->ch))
fprintf(out, "%c", h->ch);
else
fprintf(out, "%d#", (int)h->ch);
//如果是非打印字符,输出它的ASCII码,否则输出
fprintf(out, " %s\n", s.c_str());
}
}
void DispCode() {
int i;
out = fopen("12code.txt", "w+");
if (out == NULL) {
puts("输出流获取失败");
exit(1);
}
for (i = 0; i < n * 2 - 1; i++) //找树根开始遍历
if (!s[i]->pa) {
string st = "";
find(s[i], st);
break;
}
fclose(out);
}
void Encrypt() {
in = out = NULL;
in = fopen("12source1.txt", "r+");
if (in == NULL) {
puts("读入失败12source1.txt");
exit(1);
}
out = fopen("12encrypt.txt", "w+");
if (out == NULL) {
fclose(in);
puts("输出流获取失败");
exit(1);
}
int k;
while (~(k = fgetc(in))) {
fprintf(out, "%s", code[table.find(k)].c_str());
} //读入文章并根据出现的字符输出编码
fclose(in);
fclose(out);
}
int main()
{
Init();
Cal();
puts("输出哈夫曼书每个字符的编码到文件12code.txt");
DispCode();
puts("输出加密编码结果");
Encrypt();
return 0;
}
解密Decrypt.cpp
#pragma warning(disable:4996)
//#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <string>
#include <cctype>
using namespace std;
struct BTnode {
char data;
BTnode *lc, *rc;
} *root;
FILE *in, *out;
void InitBTnode(BTnode *&b) {
b = (BTnode*)malloc(sizeof(BTnode));
b->lc = b->rc = NULL;
b->data = 0;
} //初始化结点,data为0说明不是叶子结点
void Init()
{
char ch[10], cd[300], *p;
InitBTnode(root);
BTnode *pt;
int k;
in = fopen("12code.txt","r+");
if (in == NULL) {
puts("读入12code.txt失败");
exit(1);
}
while (~fscanf(in, "%s%s", ch, cd)) {
//读取符号或者符号编码,还有哈夫曼编码
if (ch[1]) {
p = ch;
k = 0;
while (*p != '#') {
k = k * 10 + *p - '0';
p++;
}
}
else k = ch[0];
//至此,符号读取完毕,编码存于k
//cout << ch << " " << k << " " << cd << endl;
p = cd;
pt = root;
//从根节点开始,按着符号编码进行遍历
while (*p) {
if (*p == '1') {
if (!pt->rc)
InitBTnode(pt->rc);
pt = pt->rc;
}//没有遍历时如果将遍历的结点为空,则新增
else {
if (!pt->lc)
InitBTnode(pt->lc);
pt = pt->lc;
}
p++;
}
pt->data = (char)k;
}
fclose(in);
in = NULL;
}
void Match() {
in = fopen("12encrypt.txt", "r+");
if (in == NULL) {
puts("读入12encrypt.txt失败");
exit(1);
}
out = fopen("12source2.txt", "w");
if (out == NULL) {
fclose(in);
puts("文件输出流获取失败12source2.txt");
exit(1);
}
int k = fgetc(in); //读取第一个编码
BTnode *pt=NULL;
while (~k) {
pt = root; //开始第一个字符的读入
while (!pt->data)
{
if (k == '1')
pt = pt->rc;
else
pt = pt->lc;
k = fgetc(in);
} //直到遍历到的结点为叶子结点,开始输出
fprintf(out, "%c", pt->data);
//cout << (char)pt->data;
}
fclose(out);
fclose(in);
}
int main()
{
Init();
Match();
return 0;
}
网友评论