haffman树

//haffman编码 使a.txt中的左右英文字母编码后 写入b.txt 之后反编码写入c.txt 对比a与c 验证是否成功

#include "stdafx.h"
#include<iostream>
#include<string>
using namespace std;

int ABC[104] = { 0 }; //每个字符 权重初始为0 前大后小
int n = 0;
bool flag[104] = { false }; //已经处理过 初始false为未处理
char text[10000]; //用text数组将a.txt里面的内容存储
char txt[10000]; //尽可能的大 否则二进制编码越界
int haffman[52][50] = {-1};
FILE *p;
int h = 0; //作为全局变量 作用于反编码过程 记录数组下标

struct node
{
int data; //仍然以数组的下标表示 字符abc
int rchild = -1; //右子树
int lchild = -1; //左子树
}nodetree[103];

//寻找数组中最小的值 返回下标
int findmin()
{
int i = 0;
int j = 0;
int weight = 0;
while (!flag[i]) i++;
j = i;
weight = ABC[i];
for (; i < 104; i++)
{
if (flag[i] == true && weight > ABC[i]) //找出字幕出现次数大于0 且最小的
{
weight = ABC[i];
j = i;
}
}
flag[j] = false; //找出的最小值下次不再参与
return j;
}

void creat()
{
for (int i = 0; i < 52+n-1; i++)
{
nodetree[i].data = i;
}
//cout << "最小值排序 :" << endl;
for (int i = 52; i <52+n-1; i++)
{
int a = findmin();
int b = findmin();
//cout << a <<" "<< ABC[a] << endl << b <<" "<<ABC[b] << endl;
//cout << char(a + 97-26) << endl;
//cout << char(b + 97-26) << endl;
nodetree[i].lchild = a;
nodetree[i].rchild = b;
ABC[i] = ABC[a] + ABC[b];
flag[i] = true;
}
cout << endl;
//for (int i = 52; i < 52 + n - 1; i++)
//{
// cout << nodetree[i].data << " " << nodetree[i].lchild << "," << nodetree[i].rchild << endl;
//}
}


int asc[50]; //用以暂时存放haffman编码
int j = -1; //j不会变化
void visittree(node tree)
{
if (tree.lchild == -1 && tree.rchild == -1) //叶子节点储存字母
{
int i = 0;

if (tree.data < 26)
cout << char(65 + tree.data) << "编码:";
else
cout << char(tree.data + 97 - 26) << "编码:";

while (asc[i] != -1)
{
haffman[tree.data][i] = asc[i];
cout << asc[i++];
}
cout << endl ;
return;
}

j++;
asc[j] = 0;
visittree(nodetree[tree.lchild]);
asc[j] = 1;
visittree(nodetree[tree.rchild]);
asc[j] = -1;
j--;

}

//输入根节点与数组下标 返回数组下标 haffman反编码
int decode(node tree,int i)
{
if (tree.lchild == -1 && tree.rchild == -1)
{
if(tree.data<26)
fprintf(p, "%c", tree.data +65);
else
fprintf(p, "%c", tree.data + 97 - 26);
return h;
}
h++;
if (text[i] == '0')
decode(nodetree[tree.lchild],i+1);
else
decode(nodetree[tree.rchild],i+1);
}

int main()
{
//进行初始化
memset(flag, false, sizeof(flag));
memset(asc, -1, sizeof(asc));
memset(haffman, -1, sizeof(haffman));

//读取已存在的文件a.txt 并把文件内容放到text数组与txt数组中 方便操作

char ch;
int i = 0;
p = fopen("E:\\a.txt", "r");
if (p == NULL)
{
printf("failed to open file. ");
exit(1);
}
cout << "原文中含有的英文字母是:" << endl;
while ((ch = getc(p)) != EOF)
{
if (ch >= 65 && ch <= 90||ch>=97&&ch<=122)
{
txt[i] = ch;
text[i++] = ch;
cout << ch;
}
}
//text[i] = '\0';
//txt[i] = '\0';
fclose(p);


//输出文件中a-z,A—Z的出现的次数 以及总共出现的字母数
cout << endl;
i = 0;
while (text[i] != '\0')//将字mu出现的次数记录作为权值写到数组ABC
{
if (text[i] <= 90)
ABC[text[i++] - 65]++;
else
ABC[text[i++] - 97 + 26]++;
}
for (i = 0; i < 26; i++)
{
cout << "字母:" << char(i + 65) << "次数:" << ABC[i] << endl;
}
for (; i < 52; i++)
{
cout << "字母:" << char(i + 97-26) << "次数:" << ABC[i] << endl;
}
for (i = 0; i < 52; i++)
{
if (ABC[i]!=0)
{
n++;
flag[i] = true;
}
}
cout <<endl<< "总共的字母数量是n:" << n << endl;

//创建haffman树 nodetree[n-2+52]作为根节点
//visittree函数将遍历所有叶子节点 并把得到的haffman编码写入二维数组haffman中
creat();
visittree(nodetree[n - 2+52]);
//输出字母的haffman编码
cout << endl << endl << endl;
for (i = 0,j=0; i < 52; i++)
{
if (ABC[i] != 0)
if (i < 26)
{
cout << char(65 + i) << "编码:";
while (haffman[i][j] != -1)
cout << haffman[i][j++];
cout << endl;
}
else
{
cout << char(i + 97-26) << "编码:";
while (haffman[i][j] != -1)
cout << haffman[i][j++];
cout << endl;
}
j = 0;
}

//创建b.txt 将text数组中的字母编码后写入
i = 0;
p = fopen("E:\\b.txt", "w");
while ((ch = text[i++])!='\0')
{
if (ch < 91)
{
j = 0;
while (haffman[ch - 65][j] != -1)
fprintf(p, "%d", haffman[ch - 65][j++]);
}
else
{
j = 0;
while (haffman[ch - 97+26][j] != -1)
fprintf(p, "%d", haffman[ch - 97+26][j++]);
}
}
fclose(p);

//输出b.txt中的内容 并存到text数组中
p = fopen("E:\\b.txt", "r");
fscanf(p, "%s", text);
printf("b.txt: %s\n", text);
fclose(p);

//创建c.txt 对text进行反编码写c.txt
p = fopen("E:\\c.txt", "w");
while (text[h] != '\0')
{
decode(nodetree[52 + n - 2], h);
}
fclose(p);
cout << endl;

//输出c.txt文件里面的内容 对比a.txt
p = fopen("E:\\c.txt", "r");
fscanf(p, "%s", text);
printf("c.txt: %s\n", text);
fclose(p);
cout << endl;
printf("a.txt: %s\n", txt);
cout << endl;

//比较a.txt与c.txt的内容
if (strcmp(text, txt) == 0)
cout << "a.txt与c.txt相等,编码成功" << endl;
else
cout << "编码失败" << endl;

getchar();
return 0;
}

猜你喜欢

转载自www.cnblogs.com/zhengbao/p/9175069.html