哈夫曼编码探究

哈夫曼编码探究

哈夫曼编码

#include <iostream>
#include <cstring>
#include <set>
#include<time.h>
#include<Windows.h>
using namespace std;

#define maxn 20000
#define STR_LEN 10//定义随机输出的数据规模。
#define CHAR_MIN 'a'
#define CHAR_MAX 'z' //定义输出随机字符串每个字符的最大最小值。

int n;                   // 字符种类 
char s[1000005];
char a[1000005];

typedef struct  node     // 结点 
{
	int weight;
	int parent, lchild, rchild;
}HufNode;
typedef struct code     // 初始结点 
{
	int weight;
	char data;
	char code[maxn];
}Hufcode;
Hufcode  h1[maxn];
HufNode   h[maxn];

void creat();
void begin();
void Init(Hufcode* h1);
void select(HufNode* h, int k, int& s1, int& s2);
void HuffmanTree(Hufcode* h1, HufNode* h);
void EnCodeing(Hufcode* h1);
int search(Hufcode* h1, char* s);
void DeCodeing(Hufcode* h1);


int main()
{
	clock_t start, finish;
	double part1,part2;
	do {
		FILE* fp = fopen("log.txt", "a");
		creat();
		begin();
		Init(h1);
		HuffmanTree(h1, h);
		start = clock();
		EnCodeing(h1);   // 加密
		finish = clock();
		part1 = (double)(finish - start) / CLOCKS_PER_SEC;
		fprintf(fp, "|--->>>\tEnCodeing time=%.3lfsec", part1);
		start=clock();
		DeCodeing(h1);   //解密 
		finish = clock();
		part2 = (double)(finish - start) / CLOCKS_PER_SEC;
		fprintf(fp, "\n|--->>>\tDeCodeing time=%.3lfsec", part2);
		time_t t;
		struct tm* st;
		t = time(NULL);
		st = localtime(&t);
		double times = (double)clock() / CLOCKS_PER_SEC;
		fprintf(fp, "\n|--->>>\ttotaltime=%.3lfsec\t\t", times);
		fprintf(fp, "%d-%d-%d %2d:%2d:%2d\n\n\n", st->tm_year + 1900, st->tm_mon + 1, st->tm_mday, st->tm_hour, st->tm_min, st->tm_sec);
		fclose(fp);
		printf("\n是否继续:(输入0截止,输入其他字符继续)\n");
	} while (getchar() != '0');

	return 0;
}

int search(Hufcode* h1, char* s)
{
	for (int i = 0; i < n; i++)
		if (strcmp(h1[i].code, s) == 0)
			return  i;
	return -1;
}

void creat()
{
	FILE* creat = fopen("需加密的文本.txt", "w");
	FILE* c2 = fopen("log.txt", "a");

	char str[STR_LEN + 1] = { 0 };
	int i;
	int lenth;
	srand(time(NULL));//通过时间函数设置随机数种子,使得每次运行结果随机。
	do { lenth = rand() % STR_LEN; } while (lenth < 3);
	for (i = 0; i < STR_LEN; i++)
	{
		if(STR_LEN<26)
			str[i] = rand() % lenth + CHAR_MIN;
		else
		str[i] = rand() % (CHAR_MAX - CHAR_MIN + 1) + CHAR_MIN; //生成要求范围内的随机数。
	}
	fprintf(creat,"%s\n", str);//输出生成的随机字符。
	if (STR_LEN < 26)
		fprintf(c2, "random select: %d\n", lenth);
	else
		fprintf(c2, "random select: NULL\n");

	fclose(creat);
	fclose(c2);
}

void begin()   // 统计需加密的文本 中字符种类数 以及各字符出现频率 
{
	FILE* fp = fopen("需加密的文本.txt", "r");
	FILE* f = fopen("log.txt", "a");
	fprintf(f, "source file:");
	memset(s, 0, sizeof(s));
	int num[26] = { 0 };
	set<int> sub;
	while (fscanf(fp, "%s", s) != EOF)
	{
		fprintf(f, "%s", s);
		for (int i = 0; s[i]; i++)
		{
			int t = s[i] - 'a';
			if (t >= 0 && t <= 25)
			{
				num[t]++;
				sub.insert(t);
			}
		}
		cout << s << endl;
	}
	fprintf(f, "\n");
	fclose(fp);
	fclose(f);

	FILE* f1 = fopen("建立哈夫曼树用.txt", "w");
	FILE* f2 = fopen("log.txt", "a");
	fprintf(f1, "%d", sub.size());
	fprintf(f2, "char count:%d", sub.size());

	for (int i = 0; i < 26; i++)
		if (num[i])
		{
			fprintf(f1, " %d%c", num[i], 97 + i);
			fprintf(f2, " %d%c", num[i], 97 + i);
		}

	fclose(f1);
	fclose(f2);
}

void Init(Hufcode* h1)            //从文件中提取叶子节点 
{

	FILE* fp = fopen("建立哈夫曼树用.txt", "r");
	fscanf(fp, "%d", &n);
	for (int i = 0; i < n; i++)
		fscanf(fp, "%d%c", &h1[i].weight, &h1[i].data);

	fclose(fp);
}

void select(HufNode* h, int k, int& s1, int& s2)		// 选择两个最小的值 (得到s1 与s2 )
{
	int i;
	for (i = 0; i < k && h[i].parent != 0; i++);				//选择一个父节点为0的根节点
	s1 = i;
	for (i = 0; i < k; i++)
		if (h[i].parent == 0 && h[i].weight < h[s1].weight)
			s1 = i;
	for (i = 0; i < k; i++)
		if (h[i].parent == 0 && i != s1)
		{
			s2 = i;
			break;
		}
	for (i = 0; i < k; i++)
		if (h[i].parent == 0 && i != s1 && h[i].weight < h[s2].weight)
			s2 = i;
}

void HuffmanTree(Hufcode* h1, HufNode* h)   //根据初始信息建立哈夫曼树 
{
	memset(s, 0, sizeof(s));
	int m = 2 * n - 1;
	for (int i = 0; i < m; i++)
	{
		if (i < n)                   //前n个全部是叶子节点,
			h[i].weight = h1[i].weight;
		else                      //后面的是还没建成的树
			h[i].weight == 0;
		h[i].lchild = h[i].parent = h[i].rchild = 0;
	}
	int s1, s2;
	for (int i = n; i < m; i++)
	{
		select(h, i, s1, s2);
		h[s1].parent = i;        //  已经选过为表示删除   父节点由零变为i ( 没选过的父亲节点仍是0 ) 
		h[s2].parent = i;
		h[i].lchild = s1;
		h[i].rchild = s2;
		h[i].weight = h[s1].weight + h[s2].weight;
	}

	s[n] = '\0';
	int l;
	for (int i = 0; i < n; ++i)
	{                          //从每个叶子节点开始倒序遍历
		l = n - 1;                //倒序赋值字符串
		for (int k = i, p = h[k].parent; p; k = p, p = h[k].parent) {   //沿着叶子回溯到根节点
			if (k == h[p].lchild)
				s[l] = '0';
			else
				s[l] = '1';
			l--;
		}
		strcpy(h1[i].code, s + l + 1);


		cout << h1[i].data << " " << h1[i].code << endl;
	}

	FILE* f1 = fopen("字符编码.txt", "w");
	FILE* f2 = fopen("log.txt", "a");

	fprintf(f2, "\nhufftree:\n");
	for (int i = 0; i < n; i++)
	{
		fprintf(f1, "%c %s\n", h1[i].data, h1[i].code);
		fprintf(f2, "%c %s\n", h1[i].data, h1[i].code);
	}

	fclose(f1);
	fclose(f2);
}

void EnCodeing(Hufcode* h1)     // 加密 
{
	FILE* fp = fopen("需加密的文本.txt", "r");
	FILE* f1 = fopen("加密后得到的电文.txt", "w");
	FILE* f2 = fopen("log.txt", "a");
	fprintf(f2, "encode result:");
	memset(s, 0, sizeof(s));
	while (fscanf(fp, "%s", s) != EOF)
	{
		for (int i = 0; s[i]; i++)
		{
			for (int j = 0; j < n; j++)
			{
				if (s[i] == h1[j].data)
				{
					fprintf(f1, "%s", h1[j].code);
					fprintf(f2, "%s", h1[j].code);
					cout << h1[j].code;
				}

			}
		}
		fprintf(f2, "\n");
	}
	cout << endl;
	fclose(fp);
	fclose(f1);
	fclose(f2);

}

void DeCodeing(Hufcode* h1)
{

	FILE* f1 = fopen("加密后得到的电文.txt", "r");
	FILE* f2 = fopen("解密后得到的文本.txt", "w");
	FILE* f3 = fopen("log.txt", "a");
	memset(s, 0, sizeof(s));
	while (fscanf(f1, "%s", s) != EOF)
	{
		fprintf(f3, "decode result:");
		memset(a, 0, sizeof(a));
		int len = strlen(s), k = 0;
		for (int i = 0; i < len; i++)
		{
			a[k] = s[i];
			a[k + 1] = '\0';
			int t = search(h1, a);
			if (t != -1)
			{

				fprintf(f2, "%c", h1[t].data);
				fprintf(f3, "%c", h1[t].data);
				cout << h1[t].data;
				k = 0;
				continue;
			}
			k++;
		}
		fprintf(f3, "\n");
	}
	fclose(f1);
	fclose(f2);
	fclose(f3);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值