文本文件压缩

项目描述:

设计一个文本文件压缩工具,哈夫曼编码是一种常用的数据压缩技术,对数据文件进行哈夫曼编码可大大缩短文件的传输长度,提高信道利用率及传输效率。要求采用哈夫曼编码原理,统计文本文件中字符出现的频率,以频率作为权值,对文件进行哈夫曼编码以达到压缩文件的目的,再用哈夫曼编码进行译码解压缩。

功能实现:

  1. 主菜单主界面与功能一览

  2. 统计词频:统计待压缩的文本文件中各字符出现的频率,以频率为权值建立哈夫曼树,并将该哈夫曼树保存到文件HufTree.dat中。 

  3. 查询该文本文件的字符:能按照频率排名降序或字符ascii码升序后的查询、分页查询、区间查询、查询倒数第N个

  4. 编码:根据哈夫曼树(保存在HufTree.dat中)对每个字符进行哈夫曼编码,并将字符编码保存到HufCode.txt文件中。

  5.  压缩:根据哈夫曼编码,将源文件进行编码得到压缩文件CodeFile.dat。

  6. 解压:将CodeFile.dat文件利用哈夫曼树译码解压,恢复为源文件。

  7. 退出系统

EasyX版:

#include<iostream>
#include<graphics.h>
#include<easyx.h>
#include<conio.h>
using namespace std;
typedef struct Chardata {
	char data;
	long long int num;
} chardata;
typedef struct Hflist {
	char data;
	long long int num;
	char *encoding;
} hflist;
typedef struct Node1 {
	int rt;
	long long int num;
	char data;
	struct Node1 *lchild,*rchild;
} Node;
//频率升序
int compare1(const void *a, const void *b) {
	return (*(chardata*)a).num - (*(chardata*)b).num;
}
//字符ASCII升序
int compare2(const void *a, const void *b) {
	return (*(chardata*)a).data - (*(chardata*)b).data;
}
//频率降序
int compare3(const void *a, const void *b) {
	return (*(chardata*)b).num - (*(chardata*)a).num;
}
//字符ASCII降序
int compare4(const void *a, const void *b) {
	return (*(chardata*)b).data - (*(chardata*)a).data;
}
ExMessage msg = {0};
int inArea(int mx, int my, int x, int y, int w, int h) {
	if (mx > x && mx < x + w && my > y && my < y + h)return 1;
	else return 0;
}
int button(int x, int y, int w, int h, const char* text) {
	int hSpace = (w - textwidth(text)) / 2;
	int vSpace = (h - textheight(text)) / 2;
	if (inArea(msg.x, msg.y, x, y, w, h))setfillcolor(RGB(204, 232, 255));
	else setfillcolor(WHITE);
	fillroundrect(x, y, x + w, y + h, 5, 5);
	outtextxy(x + hSpace, y + vSpace, text);
	if (msg.message == WM_LBUTTONDOWN && inArea(msg.x, msg.y, x, y, w, h))return 1;
	else return 0;
}
void prompt(char *txt) {
	int font_size = 40;
	initgraph(250, 250, EX_SHOWCONSOLE);
	setbkcolor(WHITE);
	setlinecolor(BLACK);
	setlinestyle(PS_SOLID, 1);
	settextcolor(BLACK);
	setbkmode(TRANSPARENT);
	while (textwidth(txt) > 212 || textheight(txt) > 40 && font_size > 5) {
		font_size--;
		settextstyle(font_size, 0, _T("楷体"));
	}
	msg.message = 0;
	while (1) {
		BeginBatchDraw();
		cleardevice();
		setfillcolor(WHITE);
		peekmessage(&msg, EX_MOUSE);
		if (kbhit()) {
			char ch = getch();
			if (ch == '\r')break;
		}
		fillroundrect(18, 50, 18 + 212, 50 + 40, 5, 5);
		outtextxy(18 + (212 - textwidth(txt)) / 2, 50 + (40 - textheight(txt)) / 2, txt);
		if (button(100, 150, 60, 25, _T("确认")))break;
		EndBatchDraw();
		msg.message = 0;
	}
	closegraph();
}
int three__interface(char string1[][100], int o[4]) {
	initgraph(700, 432, EX_SHOWCONSOLE);
	setbkcolor(WHITE);
	setlinecolor(BLACK);
	setlinestyle(PS_SOLID, 3);
	settextcolor(BLACK);
	setbkmode(TRANSPARENT);
	int result = 0;
	while (1) {
		BeginBatchDraw();
		cleardevice();
		setfillcolor(WHITE);
		settextstyle(o[0], 0, _T("楷体"));
		fillroundrect(150, 20, 150 + 400, 20 + 50, 5, 5);
		outtextxy(150 + (400 - textwidth(string1[0])) / 2, 20 + (50 - textheight(string1[0])) / 2, string1[0]);
		peekmessage(&msg, EX_MOUSE);
		settextstyle(o[1], 0, _T("楷体"));
		if (button(250, 100, 200, 60, _T(string1[1]))) {
			result = 1;
			break;
		}
		settextstyle(o[2], 0, _T("楷体"));
		if (button(250, 190, 200, 60, _T(string1[2]))) {
			result = 2;
			break;
		}
		settextstyle(o[3], 0, _T("楷体"));
		if (button(250, 280, 200, 60, _T(string1[3]))) {
			result = 3;
			break;
		}
		EndBatchDraw();
		msg.message = 0;
	}
	closegraph();
	msg.message = 0;
	return result;
}
int pagQuery_interface(chardata *a, int num, char *txt, int *flag) {
	char str1[100] = "频率", str2[100] = "字符";
	char string1[100] = "上一页", string2[100] = "返回", string3[100] = "下一页";
	initgraph(800, 220 + 60 * num, EX_SHOWCONSOLE);
	setbkcolor(WHITE);
	setlinecolor(BLACK);
	setlinestyle(PS_SOLID, 1);
	settextcolor(BLACK);
	setbkmode(TRANSPARENT);
	settextstyle(28, 0, _T("楷体"));
	int result = 0;
	while (1) {
		BeginBatchDraw();
		cleardevice();
		setfillcolor(WHITE);
		fillroundrect(200, 20, 200 + 400, 20 + 40, 5, 5);
		outtextxy(200 + (400 - textwidth(txt)) / 2, 20 + (40 - textheight(txt)) / 2, txt);
		fillroundrect(100, 80, 100 + 240, 80 + 40, 5, 5);
		outtextxy(100 + (240 - textwidth(str2)) / 2, 80 + (40 - textheight(str2)) / 2, str2);
		fillroundrect(460, 80, 460 + 240, 80 + 40, 5, 5);
		outtextxy(460 + (240 - textwidth(str1)) / 2, 80 + (40 - textheight(str1)) / 2, str1);
		peekmessage(&msg, EX_MOUSE);
		if (kbhit()) {
			char ch = getch();
			if (ch == '\r')break;
		}
		for (int i = 1; i <= num; i++) {
			if (a[i - 1].num == 0)continue;
			fillroundrect(100, 80 + i * 60, 100 + 240, 80 + i * 60 + 40, 5, 5);
			outtextxy(100 + (240 - textwidth(a[i - 1].data)) / 2, 80 + i * 60 + (40 - textheight(a[i - 1].data)) / 2, a[i - 1].data);
			char temp[100] = {'\0'};
			sprintf(temp, "%d", a[i - 1].num);
			fillroundrect(460, 80 + i * 60, 460 + 240, 80 + i * 60 + 40, 5, 5);
			outtextxy(460 + (240 - textwidth(temp)) / 2, 80 + i * 60 + (40 - textheight(temp)) / 2, temp);
		}
		if (flag[0] == 0) {
			if (button(35, 140 + num * 60, 220, 40, _T(string1))) {
				result = -1;
				break;
			}
		}
		if (button(290, 140 + num * 60, 220, 40, _T(string2))) {
			result = 0;
			break;
		}
		if (flag[1] == 0) {
			if (button(545, 140 + num * 60, 220, 40, _T(string3))) {
				result = 1;
				break;
			}
		}
		EndBatchDraw();
		msg.message = 0;
	}
	closegraph();
	msg.message = 0;
	return result;
}
void charnum(char *str, long long int num) {
	sprintf(str, "%lld", num);
}
void filerenamecheck(char *a, char *fileExtension) {
	char b[10000] = {'\0'};
	strncpy(b, a, sizeof(b) -1);
	strncat(b, fileExtension, sizeof(b) - strlen(b) -1);
	FILE *file = fopen(b, "r");
	if (!file)return ;
	fclose(file);
	long long int count = 1;
	char c[100] = {'\0'}, d[100] = {'\0'};
	while (1) {
		c[0] = '(';
		c[1] = '\0';
		charnum(d, count);
		strcat(c, d);
		long long int length = strlen(c), temp_length = strlen(fileExtension);
		c[length] = ')';
		c[length + 1] = '\0';
		b[0] = '\0';
		strncpy(b, a, sizeof(b) -1);
		strcat(b, c);
		char e[100] = {'\0'};
		strncpy(e, b, sizeof(e) -1);
		strcat(e, fileExtension);
		file = fopen(e, "r");
		if (!file) {
			a[0] = '\0';
			strncpy(a, b, strlen(b) +1);
			fclose(file);
			return ;
		}
		fclose(file);
		count++;
	}
}
void savehufTree_1(FILE *a, Node *root) {
	if (root == NULL)return ;
	fprintf(a, "%d %d %d ", root->rt, root->num, root->data);
	if (root->lchild != NULL)fprintf(a, "%d %d %d ", root->lchild->rt, root->lchild->num, root->lchild->data);
	else fprintf(a, "-1 -1 -1 ");
	if (root->rchild != NULL)fprintf(a, "%d %d %d\n", root->rchild->rt, root->rchild->num, root->rchild->data);
	else fprintf(a, "-1 -1 -1\n");
	savehufTree_1(a, root->lchild);
	savehufTree_1(a, root->rchild);
}
int savehfuTree(Node *root, int size, char *c) {
	FILE *a;
	char b[100] = "HufTree";
	char d[10] = ".dat";
	filerenamecheck(b, d);
	strcat(b, ".dat");
	strcpy(c, b);
	a = fopen(b, "w");
	if (a == NULL) {
		char str[100] = {'\0'};
		sprintf(str, "文件%s打开失败!", b);
		perror(str);
		prompt(str);
		return -1;
	}
	fprintf(a, "%d\n", size);
	savehufTree_1(a, root);
	fclose(a);
	return 0;
}
Node* nodecreate(char data, int num) {
	Node *a = (Node*)malloc(sizeof(Node));
	if (a == NULL) {
		char o1[100] = "节点创建失败!";
		perror(o1);
		prompt(o1);
		return NULL;
	}
	a->rt = -1;
	a->data = data;
	a->num = num;
	a->lchild = NULL, a->rchild = NULL;
	return a;
}
int hfencordlist_1(Node* root, hflist* a, long long int *current_size, long long int size, char b[], long long int top) {
	if (*current_size >= size || root == NULL)return -1;
	if (root->data != '\0') {
		a[*current_size].data = root->data;
		a[*current_size].num = root->num;
		if (top == 0 && size == 1) {
			top = 1;
			b[0] = '0';
		}
		char *temp = (char*)malloc((top + 1) * sizeof(char));
		if (temp == NULL) {
			char str1[100] = "数组temp内存分配失败!";
			perror(str1);
			prompt(str1);
			return -1;
		}
		temp[top] = '\0';
		memcpy(temp, b, top);
		a[*current_size].encoding = temp;
		(*current_size)++;
	}
	b[top] = '0', b[top + 1] = '\0';
	hfencordlist_1(root->lchild, a, current_size, size, b, top + 1);
	b[top] = '1', b[top + 1] = '\0';
	hfencordlist_1(root->rchild, a, current_size, size, b, top + 1);
	return 0;
}
hflist* hfencordlist(Node *root, int num) {
	hflist *a = (hflist*)malloc(num * sizeof(hflist));
	if (a == NULL) {
		char o1[100] = "数组a内存分配失败!";
		perror(o1);
		prompt(o1);
		return NULL;
	}
	long long int size = 0;
	char b[300] = {'\0'};
	int temp = hfencordlist_1(root, a, &size, num, b, 0);
	if (temp == -1) {
		free(a);
		return NULL;
	}
	return a;
}
Node* buildTree(long long int size, Node **record, long long int *returnsize) {
	if (size < 2)return record[0];
	long long int top = size;
	long long int count1 = 0;
	Node *root = NULL;
	for (int i = 0; i < size - 1; i++) {
		int min = 0;
		for (int j = 0; j < top; j++) {
			if (record[j]->num < record[min]->num)min = j;
		}
		int secmin = (min == 0) ? 1 : 0;
		for (int j = 0; j < top; j++) {
			if (j == min)continue;
			if (record[j]->num < record[secmin]->num)secmin = j;
		}
		if (record[min]->rt == -1)record[min]->rt = count1++;
		if (record[secmin]->rt == -1)record[secmin]->rt = count1++;
		root = nodecreate('\0', record[min]->num + record[secmin]->num);
		if (root == NULL)return NULL;
		root->lchild = record[min], root->rchild = record[secmin];
		if (root->rt == -1)root->rt = count1++;
		int temp1 = min > secmin ? secmin : min;
		int temp2 = min > secmin ? min : secmin;
		record[temp1] = root;
		record[temp2] = record[top - 1];
		top--;
	}
	*returnsize = count1;
	return root;
}
long long int CalculatedLength(hflist const *a, int const num) {
	long long int length = 0;
	for (int i = 0; i < num; i++) {
		length += (long long int)strlen(a[i].encoding) * (long long int)a[i].num;
	}
	return length;
}
chardata *statisticalTxt(char const *FileName, long long int *returnSize) {
	FILE *a;
	a = fopen(FileName, "r");
	if (a == NULL) {
		char o1[100] = {'\0'};
		sprintf(o1, "文件%s打开失败!", FileName);
		perror(o1);
		prompt(o1);
		return NULL;
	}
	chardata *b = (chardata*)calloc(256, sizeof(chardata));
	if (b == NULL) {
		char o1[100] = "数组b内存分配失败!";
		perror(o1);
		prompt(o1);
		fclose(a);
		return NULL;
	}
	char temp = '\0';
	*returnSize = 0;
	while (fscanf(a, "%c", &temp) != EOF) {
		if (b[(unsigned char)temp].num == 0) {
			b[(unsigned char)temp].data = temp;
			(*returnSize)++;
		}
		b[(unsigned char)temp].num++;
	}
	fclose(a);
	chardata *c = (chardata*)malloc(*returnSize * sizeof(chardata));
	if (c == NULL) {
		char o1[100] = "数组c内存分配失败!";
		perror(o1);
		prompt(o1);
		fclose(a);
		free(b);
		return NULL;
	}
	for (int i = 0, j = 0; i < 256; i++) {
		if (b[i].num > 0) {
			c[j] = b[i];
			j++;
		}
	}
	qsort(c, *returnSize, sizeof(chardata), compare1);
	free(b);
	return c;
}
char* nameinput(char *txt) {
	initgraph(700, 432, EX_SHOWCONSOLE);
	setbkcolor(RGB(18, 237, 241));
	char input[10000] = {'\0'};
	int length = 0;
	bool isActive = true;
	msg.message = 0;
	while (1) {
		if (kbhit()) {
			char ch = getch();
			if (ch == '\r' && length > 0) {
				isActive = false;
				break;
			} else if (ch == '\b') {
				if (length > 0) {
					input[--length] = '\0';
				}
			} else if (ch >= 32 && ch <= 126) {
				if (length < sizeof(input) -1) {
					input[length++] = ch;
					input[length] = '\0';
				}
			}
		}
		BeginBatchDraw();
		cleardevice();
		setfillcolor(WHITE);
		settextcolor(BLACK);
		setlinestyle(PS_SOLID, 2);
		setlinecolor(BLACK);
		settextcolor(BLACK);
		setbkmode(TRANSPARENT);
		fillrectangle(200, 30, 500, 70);
		settextstyle(20, 0, _T("楷体"));
		outtextxy(200 + (300 - textwidth(txt)) / 2, 30 + (40 - textheight(txt)) / 2, txt);
		fillrectangle(100, 150, 600, 200);
		settextstyle(28, 0, _T("Consolas"));
		outtextxy(105, 161, input);
		static int counter = 0;
		if (isActive && (++counter % 30) < 15) {
			int w = textwidth(input);
			line(105 + w, 161, 105 + w, 188);
		}
		EndBatchDraw();
		Sleep(20);
	}
	char *returnstring = (char*)malloc((length + 1) * sizeof(char));
	if (returnstring == NULL) {
		char o1[100] = "数组returnstring内存分配失败!";
		perror(o1);
		prompt(o1);
		return NULL;
	}
	strcpy(returnstring, input);
	returnstring[length] = '\0';
	closegraph();
	msg.message = 0;
	return returnstring;
}
char *filenaming(char *fileExtension) {
	char *s, s0[10000] = "请输入期望文件名:", s1[1000] = "警告:该文件名不可用!";
	while (1) {
		int flag = 0;
		s = nameinput(s0);
		if (s == NULL)return NULL;
		for (int i = 0; s[i] != '\0'; i++) {
			if (s[i] == '\\' || s[i] == '/' || s[i] == ':' || s[i] == '*' ||
			s[i] == '?' || s[i] == '"' || s[i] == '<' || s[i] == '>' || s[i] == '|') {
				flag = 1;
				break;
			}
		}
		if (!flag)break;
		else prompt(s1);
	}
	char *a = (char*)malloc((strlen(s) +5) * sizeof(char));
	if (a == NULL) {
		char o1[100] = "数组a分配失败!";
		perror(o1);
		prompt(o1);
		return NULL;
	}
	strcpy(a, s);
	filerenamecheck(a, fileExtension);
	strcat(a, fileExtension);
	a[strlen(a)] = '\0';
	return a;
}
int compress_1(char const *FileName, hflist const *a, int const num, char *treefile) {
	FILE *b,*d;
	long long int length = CalculatedLength(a, num);
	hflist *list = (hflist*)malloc(256 * sizeof(hflist));
	if (list == NULL) {
		char o1[100] = "数组list内存分配失败!";
		perror(o1);
		prompt(o1);
		return -1;
	}
	for (int i = 0; i < num; i++) {
		int index = 0;
		index = (unsigned char)a[i].data;
		list[index] = a[i];
	}
	b = fopen(FileName, "r");
	if (b == NULL) {
		char o1[100] = {'\0'};
		sprintf(o1, "文件%s打开失败!", FileName);
		perror(o1);
		prompt(o1);
		return -1;
	}
	char y[10] = ".dat";
	char *x = filenaming(y);
	if (x == NULL)return -1;
	d = fopen(x, "wb");
	if (d == NULL) {
		char o1[100] = {'\0'};
		sprintf(o1, "文件%s打开失败!", x);
		perror(o1);
		prompt(o1);
		return -1;
	}
	int length1 = strlen(treefile);
	fwrite(&length1, sizeof(int), 1, d);
	fwrite(treefile, sizeof(char), length1, d);
	fwrite(&length, sizeof(long long int), 1, d);
	int bit = 0;
	char temp = '\0';
	char data = 0;
	while (fscanf(b, "%c", &temp) != EOF) {
		if (list[(unsigned char)temp].encoding == NULL)continue;
		int c = strlen(list[(unsigned char)temp].encoding);
		for (int i = 0; i < c; i++) {
			if (bit >= 8) {
				fputc(data, d);
				bit = 0;
				data = 0;
			}
			if (list[(unsigned char)temp].encoding[i] == '1') {
				data |= (1 << (7 - bit));
			}
			bit++;
		}
	}
	free(x);
	fputc(data, d);
	fclose(b);
	fclose(d);
	return 0;
}
Node *rebuildTree(char *treefile) {
	FILE *x;
	x = fopen(treefile, "r");
	if (x == NULL) {
		char o1[100] = {'\0'};
		sprintf(o1, "文件%s打开失败!", treefile);
		perror(o1);
		prompt(o1);
		return NULL;
	}
	int count1 = 0;
	fscanf(x, "%d\n", &count1);
	Node **record = (Node**)malloc((count1 + 1) * sizeof(Node*));
	if (record == NULL) {
		char o1[100] = "数组record内存分配失败!";
		perror(o1);
		prompt(o1);
		return NULL;
	}
	for (int i = 0; i <= count1; i++) {
		record[i] = NULL;
	}
	for (int i = 0; i < count1; i++) {
		int a[3] = {0}, b[3] = {0}, c[3] = {0};
		fscanf(x, "%d %d %d %d %d %d %d %d %d\n", &a[0],
		       &a[1], &a[2], &b[0], &b[1], &b[2], &c[0], &c[1], &c[2]);
		if (record[a[0]] == NULL) {
			Node*temp = nodecreate((char)a[2], a[1]);
			if (temp == NULL)return NULL;
			temp->rt = a[0];
			record[a[0]] = temp;
		}
		if (b[0] != -1 && record[b[0]] == NULL) {
			Node*temp = nodecreate((char)b[2], b[1]);
			if (temp == NULL)return NULL;
			temp->rt = b[0];
			record[b[0]] = temp;
		}
		if (c[0] != -1 && record[c[0]] == NULL) {
			Node*temp = nodecreate((char)c[2], c[1]);
			if (temp == NULL)return NULL;
			temp->rt = c[0];
			record[c[0]] = temp;
		}
		if (b[0] != -1)record[a[0]]->lchild = record[b[0]];
		if (c[0] != -1)record[a[0]]->rchild = record[c[0]];
	}
	Node *root = record[count1 - 1];
	free(record);
	fclose(x);
	return root;
}
char *filePathcheck(char *a) {
	int length = strlen(a), j = 0;
	char *b = (char*)malloc(2 * length * sizeof(char));
	if (b == NULL) {
		char o1[100] = "数组b内存分配失败!";
		perror(o1);
		prompt(o1);
		return NULL;
	}
	for (int i = 0; i < length; i++) {
		if (a[i] == '\\')b[j++] = a[i];
		b[j++] = a[i];
	}
	b[j] = '\0';
	free(a);
	return b;
}
char *name() {
	char b[1000] = "请输入文件名或文件路径:";
	char *s = nameinput(b);
	if (s == NULL)return NULL;
	char *a = filePathcheck(s);
	return a;
}
void freeTree(Node *root) {
	if (root == NULL)return ;
	Node* l = root->lchild,*r = root->rchild;
	free(root);
	freeTree(l);
	freeTree(r);
}
int decode() {
	int flag = 0;
	char *Filename = name();
	if (Filename == NULL)return 1;
	FILE *a,*b;
	a = fopen(Filename, "rb");
	if (a == NULL) {
		char o[1000] = {'\0'};
		sprintf(o, "文件%s不存在!", Filename);
		prompt(o);
		fclose(a);
		return 1;
	}
	char c[10] = ".txt";
	char *Filename1 = filenaming(c);
	if (Filename1 == NULL) {
		fclose(a);
		return 1;
	}
	b = fopen(Filename1, "w");
	if (b == NULL) {
		char x[1000] = {'\0'};
		sprintf(x, "文件%s创建失败!", Filename1);
		prompt(x);
		fclose(a);
		fclose(b);
		return 1;
	}
	int length1 = 0;
	long long int length = 0;
	fread(&length1, sizeof(int), 1, a);
	char *treefile = (char*)malloc((length1 + 1) * sizeof(char));
	if (treefile == NULL) {
		char o1[100] = "数组treefile内存分配失败!";
		perror(o1);
		prompt(o1);
		return 1;
	}
	fread(treefile, sizeof(char), length1, a);
	fread(&length, sizeof(long long int), 1, a);
	long long int size = (length + 7) / 8;
	char *data = (char*)malloc(size * sizeof(char));
	if (data == NULL) {
		char o1[100] = "数组data内存分配失败!";
		perror(o1);
		prompt(o1);
		return 1;
	}
	fread(data, sizeof(char), size, a);
	Node *root = rebuildTree(treefile),*current_node = NULL;
	if (root == NULL)flag = 1;
	current_node = root;
	for (int i = 0; i < size && flag != 1; i++) {
		int bit = 7;
		while (bit >= 0) {
			if (current_node->rchild == NULL) {
				fprintf(b, "%c", current_node->data);
				current_node = root;
			}
			if ((data[i] >> bit) & 1) {
				current_node = current_node->rchild;
			} else current_node = current_node->lchild;
			bit--;
		}
	}
	free(treefile);
	free(Filename1);
	free(data);
	fclose(a);
	fclose(b);
	freeTree(root);
	return flag;
}
int savehfulist(hflist *list, int num) {
	FILE *a;
	char b[100] = "HufCode";
	char c[10] = ".txt";
	filerenamecheck(b, c);
	strcat(b, ".txt");
	a = fopen(b, "w");
	if (a == NULL) {
		char str[100] = {'\0'};
		sprintf(str, "文件%s打开失败!", b);
		perror(str);
		prompt(str);
		return -1;
	}
	for (int i = 0; i < num; i++) {
		fprintf(a, "%d %d %s\n", list[i].data, list[i].num, list[i].encoding);
	}
	fclose(a);
	return 0;
}
void freelist(hflist *a, int num) {
	for (int i = 0; i < num; i++) {
		free(a[i].encoding);
	}
}
int compress_main() {
	long long int num = 0, count1 = 0;
	char *filename = name();
	chardata *b = statisticalTxt(filename, &num);
	if (b == NULL)return 1;
	Node *root = NULL;
	Node **record = (Node**)malloc(num * sizeof(Node*));
	if (record == NULL) {
		char o1[100] = "数组record内存分配失败!";
		perror(o1);
		prompt(o1);
		free(b);
		return 1;
	}
	for (int i = 0; i < num; i++) {
		Node *temp = nodecreate(b[i].data, b[i].num);
		if (temp == NULL)return 1;
		record[i] = temp;
	}
	root = buildTree(num, record, &count1);
	if (root == NULL)return 1;
	hflist *c = hfencordlist(root, num);
	if (c == NULL) {
		free(b);
		return 1;
	}
	char treefile[100] = {'\0'};
	int temp = savehfuTree(root, count1, treefile);
	if (temp == -1) {
		free(b);
		return 1;
	}
	int temp1 = compress_1(filename, c, num, treefile);
	if (temp1 == -1) {
		free(b);
		return 1;
	}
	int temp2 = savehfulist(c, num);
	if (temp2 == -1) {
		free(b);
		return 1;
	}
	free(b);
	free(filename);
	freeTree(root);
	free(record);
	freelist(c, num);
	free(c);
	return 0;
}
int object_print() {
	char a[4][100] = {"请选择排序对象:", "频率", "字符ASCII值", "返回"};
	int b[4] = {32, 32, 32, 32};
	int result = three__interface(a, b);
	return result;
}
int SortOrder() {
	char a[4][100] = {"请选择排序顺序:", "升序", "降序", "返回"};
	int b[4] = {32, 32, 32, 32};
	int result = three__interface(a, b);
	return result;
}
void chardataHandle(chardata **a, int object, int order, int num) {
	if (object == 1 && order == 1) {
		qsort(*a, num, sizeof(chardata), compare1);
	}
	if (object == 2 && order == 1) {
		qsort(*a, num, sizeof(chardata), compare2);
	}
	if (object == 1 && order == 2) {
		qsort(*a, num, sizeof(chardata), compare3);
	}
	if (object == 2 && order == 2) {
		qsort(*a, num, sizeof(chardata), compare4);
	}
}
int reasonableJudgment(int max) {
	int a = 0;
	while (1) {
		char str[100] = "请输入位序:";
		char *b = nameinput(str);
		if (b == NULL)return -1;
		a = atoi(b);
		if (a <= 0 || a > max) {
			char c[100] = "数据不合理,请重新输入!";
			prompt(c);
		} else break;
	}
	return a;
}
int selection(int a(), int *data) {
	while (1) {
		int b = a();
		if (b == 1) {
			*data = 1;
			break;
		} else if (b == 2) {
			*data = 2;
			break;
		} else return 1;
	}
	return 0;
}
int BasicSelection(int *object, int *order) {
	while (1) {
		int a = selection(SortOrder, order);
		if (a == 1)return 1;
		int b = selection(object_print, object);
		if (b != 1)break;
	}
	return 0;
}
int sequence(chardata *a, int flag, int num, int way) {
	int object = 1, order = 1;
	if (flag == 1 && BasicSelection(&object, &order))return 1;
	chardataHandle(&a, object, order, num);
	int c = reasonableJudgment(num);
	if (c == -1)return -1;
	char str[1000] = {'\0'}, numchar[100] = {'\0'};
	if (way == 1) {
		sprintf(str, "顺序第%d个字符是%c。", c, a[c - 1].data);
	} else {
		sprintf(str, "逆序第%d个字符是%c。", c, a[num - c].data);
	}
	prompt(str);
	return 0;
}
int four_interface(char a[][100]) {
	initgraph(700, 432, EX_SHOWCONSOLE);
	setbkcolor(WHITE);
	setlinecolor(BLACK);
	setlinestyle(PS_SOLID, 3);
	settextcolor(BLACK);
	setbkmode(TRANSPARENT);
	settextstyle(32, 0, _T("楷体"));
	int result = 0;
	while (1) {
		BeginBatchDraw();
		cleardevice();
		setfillcolor(WHITE);
		fillroundrect(150, 20, 150 + 400, 20 + 50, 5, 5);
		outtextxy(150 + (400 - textwidth(a[0])) / 2, 20 + (50 - textheight(a[0])) / 2, a[0]);
		peekmessage(&msg, EX_MOUSE);
		if (button(250, 100, 200, 50, _T(a[1]))) {
			result = 1;
			break;
		}
		if (button(250, 180, 200, 50, _T(a[2]))) {
			result = 2;
			break;
		}
		if (button(250, 260, 200, 50, _T(a[3]))) {
			result = 3;
			break;
		}
		if (button(250, 340, 200, 50, _T(a[4]))) {
			result = 4;
			break;
		}
		EndBatchDraw();
		msg.message = 0;
	}
	closegraph();
	msg.message = 0;
	return result;
}
int five_interface(char string1[6][100]) {
	initgraph(700, 432, EX_SHOWCONSOLE);
	setbkcolor(WHITE);
	setlinecolor(BLACK);
	setlinestyle(PS_SOLID, 3);
	settextcolor(BLACK);
	setbkmode(TRANSPARENT);
	int result = 0;
	while (1) {
		BeginBatchDraw();
		cleardevice();
		setfillcolor(WHITE);
		fillroundrect(150, 20, 150 + 400, 20 + 50, 5, 5);
		outtextxy(150 + (400 - textwidth(string1[0])) / 2, 20 + (50 - textheight(string1[0])) / 2, string1[0]);
		peekmessage(&msg, EX_MOUSE);
		settextstyle(28, 0, _T("楷体"));
		if (button(250, 100, 200, 40, _T(string1[1]))) {
			result = 1;
			break;
		}
		settextstyle(32, 0, _T("楷体"));
		if (button(250, 170, 200, 40, _T(string1[2]))) {
			result = 2;
			break;
		}
		settextstyle(28, 0, _T("楷体"));
		if (button(250, 240, 200, 40, _T(string1[3]))) {
			result = 3;
			break;
		}
		settextstyle(32, 0, _T("楷体"));
		if (button(250, 310, 200, 40, _T(string1[4]))) {
			result = 4;
			break;
		}
		if (button(250, 380, 200, 40, _T(string1[5]))) {
			result = 5;
			break;
		}
		EndBatchDraw();
		msg.message = 0;
	}
	closegraph();
	msg.message = 0;
	return result;
}
int charQuery(chardata *a, int num) {
	while (1) {
		char string1[6][100] = {"请选择查询顺序:", "顺序(默认选择)", "顺序", "逆序(默认选择)", "逆序", "返回"};
		int b = five_interface(string1), temp = 0;
		if (b == 1) {
			temp = sequence(a, 0, num, 1);
			if (temp == -1)return 1;
			if (!temp)break;
		} else if (b == 2) {
			temp = sequence(a, 1, num, 1);
			if (temp == -1)return 1;
			if (!temp)break;
		} else if (b == 3) {
			temp = sequence(a, 0, num, 2);
			if (temp == -1)return 1;
			if (!temp)break;
		} else if (b == 4) {
			temp = sequence(a, 1, num, 2);
			if (temp == -1)return 1;
			if (!temp)break;
		} else return 1;
	}
	return 0;
}
int intervalQuery_print() {
	char a[4][100] = {"请选择查询对象:", "字符频率区间", "字符ASCII值区间", "返回"};
	int b[4] = {32, 32, 24, 32};
	int result = three__interface(a, b);
	return result;
}
int *findinterval(int *returnsize, chardata *a, int num, int frist, int last, int flag) {
	int *b = (int*)malloc(num * sizeof(int));
	if (b == NULL) {
		char o1[100] = "数组b内存分配失败!";
		perror(o1);
		prompt(o1);
		return NULL;
	}
	*returnsize = 0;
	for (int i = 0; i < num; i++) {
		if (flag == 1 && a[i].num <= last && a[i].num >= frist)b[(*returnsize)++] = i;
		if (flag == 2 && a[i].data <= last && a[i].data >= frist)b[(*returnsize)++] = i;
	}
	return b;
}
int pagQueryprint(int num) {
	int a = 0;
	while (1) {
		char str0[100] = "请输入每页展示数量:", str1[100] = "数据不合理,请重新输入!";
		char *b = nameinput(str0);
		if (b == NULL)return -1;
		a = atoi(b);
		if (a <= num && a > 0)break;
		else prompt(str1);
	}
	return a;
}
void pagHandle(chardata *a, chardata *b, int count1, int num, int pagnum, int *flag) {
	memset(b, 0, count1 * sizeof(chardata));
	for (int i = (pagnum - 1) * count1, j = 0; i < pagnum * count1 && i < num; i++, j++) {
		b[j] = a[i];
	}
	if (pagnum == 1)flag[0] = 1;
	if (num - pagnum * count1 <= 0)flag[1] = 1;
}
int allQuery(chardata*a, int num) {
	char str[100] = "字符频率查询";
	int order = SortOrder(), object = object_print();
	chardataHandle(&a, object, order, num);
	int count1 = pagQueryprint(num), pagnum = 1;
	if (count1 == -1)return 1;
	chardata *b = (chardata*)malloc(count1 * sizeof(chardata));
	if (b == NULL) {
		char o1[100] = "数组b内存分配失败!";
		perror(o1);
		prompt(o1);
		return 1;
	}
	while (1) {
		int flag[2] = {0};
		pagHandle(a, b, count1, num, pagnum, flag);
		int c = pagQuery_interface(b, count1, str, flag);
		if (c != 0 && (!(pagnum == 1 && c == -1)))pagnum += c;
		else break;
	}
	free(b);
	return 0;
}
int intervalpag(chardata *a, int num, char *str) {
	int count1 = pagQueryprint(num), pagnum = 1;
	chardata *b = (chardata*)malloc(count1 * sizeof(chardata));
	if (b == NULL) {
		char o1[100] = "数组b内存分配失败!";
		perror(o1);
		prompt(o1);
		return -1;
	}
	while (1) {
		int flag[2] = {0};
		pagHandle(a, b, count1, num, pagnum, flag);
		int c = pagQuery_interface(b, count1, str, flag);
		if (c != 0 && (!(pagnum == 1 && c == -1)))pagnum += c;
		else break;
	}
	return 0;
}
int interval(chardata *a, int num, int b) {
	int frist = 0, last = 0;
	char str0[100] = "数据不合理,请重新输入!";
	while (1) {
		char str[100] = "请输入区间起始位置:";
		char *temp = nameinput(str);
		if (temp == NULL)return -1;
		frist = atoi(temp);
		if (frist > 0 && frist < num)break;
		else prompt(str0);
	}
	while (1) {
		char str1[100] = "请输入区间末尾位置:";
		char *temp = nameinput(str1);
		if (temp == NULL)return -1;
		last = atoi(temp);
		if (((b == 1 && last <= a[0].num) || (b == 2 && last <= 256)) && last > frist)break;
		else prompt(str0);
	}
	int size = 0;
	int *c = findinterval(&size, a, num, frist, last, b);
	if (c == NULL)return -1;
	char str2[100] = "该区间无符合值!";
	if (size == 0)prompt(str2);
	else {
		char str3[1000] = {'\0'}, temp[100] = {'\0'};
		if (b == 1) {
			sprintf(str3, "字符频率从%d到%d有:", frist, last);
		} else {
			sprintf(str3, "字符ASCII值从%d到%d有:", frist, last);
		}
		chardata *d = (chardata*)malloc(size * sizeof(chardata));
		if (d == NULL) {
			char o1[100] = "数组d内存分配失败!";
			perror(o1);
			prompt(o1);
			return -1;
		}
		for (int i = 0; i < size; i++) {
			d[i] = a[c[i]];
		}
		int e = intervalpag(d, size, str3);
		if (e == -1)return -1;
	}
	free(c);
	return 0;
}
int intervalQuery(chardata *a, int num) {
	qsort(a, num, sizeof(chardata), compare3);
	while (1) {
		int b = intervalQuery_print();
		if (b > 0 && b < 3) {
			if (!interval(a, num, b))break;
		} else return 1;
	}
	return 0;
}
int statistics_main() {
	char *a = name();
	int v = 0;
	long long int num = 0;
	chardata *b = statisticalTxt(a, &num);
	if (b == NULL)return -1;
	while (1) {
		char string1[5][100] = {"请选择查询方式:", "单字符查询", "区间查询", "查询全部", "返回"};
		int c = four_interface(string1);
		if (c == 1)charQuery(b, num);
		else if (c == 2)intervalQuery(b, num);
		else if (c == 3) {
			v = allQuery(b, num);
			if (v)return -1;
		} else return 1;
	}
	free(a);
	return 0;
}
int main() {
	//freopen("nul", "w", stderr);
	while (1) {
		char txt[5][100] = {"文本文件压缩", "压缩文件", "解压文件", "字符频率查询", "退出"};
		int a = four_interface(txt);
		char a1[1000] = "成功!", a2[1000] = "失败!", a3[1000] = "请输入有效选择!";
		if (a == 1) {
			if (!compress_main())prompt(a1);
			else prompt(a2);
		} else if (a == 2) {
			if (!decode())prompt(a1);
			else prompt(a2);
		} else if (a == 3) {
			if (statistics_main() == -1)prompt(a2);
		} else if (a == 4)break;
		else prompt(a3);
	}
	return 0;
}

C语言版:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct Chardata {
	char data;
	long long int num;
} chardata;
typedef struct Hflist {
	char data;
	long long int num;
	char *encoding;
} hflist;
typedef struct Node1 {
	int rt;
	long long int num;
	char data;
	struct Node1 *lchild,*rchild;
} Node;
//频率升序
int compare1(const void *a, const void *b) {
	return (*(chardata*)a).num - (*(chardata*)b).num;
}
//字符ASCII升序
int compare2(const void *a, const void *b) {
	return (*(chardata*)a).data - (*(chardata*)b).data;
}
//频率降序
int compare3(const void *a, const void *b) {
	return (*(chardata*)b).num - (*(chardata*)a).num;
}
//字符ASCII降序
int compare4(const void *a, const void *b) {
	return (*(chardata*)b).data - (*(chardata*)a).data;
}
void charnum(char *str, long long int num) {
	sprintf(str, "%lld", num);
}
void filerenamecheck(char *a, char *fileExtension) {
	char b[10000] = {'\0'};
	strncpy(b, a, sizeof(b) -1);
	strncat(b, fileExtension, sizeof(b) - strlen(b) -1);
	FILE *file = fopen(b, "r");
	if (!file)return ;
	fclose(file);
	long long int count = 1;
	char c[100] = {'\0'}, d[100] = {'\0'};
	while (1) {
		c[0] = '(';
		c[1] = '\0';
		charnum(d, count);
		strcat(c, d);
		long long int length = strlen(c), temp_length = strlen(fileExtension);
		c[length] = ')';
		c[length + 1] = '\0';
		b[0] = '\0';
		strncpy(b, a, sizeof(b) -1);
		strcat(b, c);
		char e[100] = {'\0'};
		strncpy(e, b, sizeof(e) -1);
		strcat(e, fileExtension);
		file = fopen(e, "r");
		if (!file) {
			a[0] = '\0';
			strncpy(a, b, strlen(b) +1);
			fclose(file);
			return ;
		}
		fclose(file);
		count++;
	}
}
void savehufTree_1(FILE *a, Node *root) {
	if (root == NULL)return ;
	fprintf(a, "%d %d %d ", root->rt, root->num, root->data);
	if (root->lchild != NULL)fprintf(a, "%d %d %d ", root->lchild->rt, root->lchild->num, root->lchild->data);
	else fprintf(a, "-1 -1 -1 ");
	if (root->rchild != NULL)fprintf(a, "%d %d %d\n", root->rchild->rt, root->rchild->num, root->rchild->data);
	else fprintf(a, "-1 -1 -1\n");
	savehufTree_1(a, root->lchild);
	savehufTree_1(a, root->rchild);
}
void savehfuTree(Node *root, int size, char *c) {
	FILE *a;
	char b[100] = "HufTree";
	char d[10] = ".dat";
	filerenamecheck(b, d);
	strcat(b, ".dat");
	strcpy(c, b);
	a = fopen(b, "w");
	fprintf(a, "%d\n", size);
	savehufTree_1(a, root);
	fclose(a);
}
int enterNumbers() {
	char temp[100000] = {'\0'};
	scanf("%99999s", temp);
	return atoi(temp);
}
Node* nodecreate(char data, int num) {
	Node *a = (Node*)malloc(sizeof(Node));
	a->rt = -1;
	a->data = data;
	a->num = num;
	a->lchild = NULL, a->rchild = NULL;
	return a;
}
void hfencordlist_1(Node* root, hflist* a, long long int *current_size, long long int size, char b[], long long int top) {
	if (*current_size >= size || root == NULL)return ;
	if (root->data != '\0') {
		a[*current_size].data = root->data;
		a[*current_size].num = root->num;
		if (top == 0 && size == 1) {
			top = 1;
			b[0] = '0';
		}
		char *temp = (char*)malloc((top + 1) * sizeof(char));
		temp[top] = '\0';
		memcpy(temp, b, top);
		a[*current_size].encoding = temp;
		(*current_size)++;
	}
	b[top] = '0', b[top + 1] = '\0';
	hfencordlist_1(root->lchild, a, current_size, size, b, top + 1);
	b[top] = '1', b[top + 1] = '\0';
	hfencordlist_1(root->rchild, a, current_size, size, b, top + 1);
}
hflist* hfencordlist(Node *root, int num) {
	hflist *a = (hflist*)malloc(num * sizeof(hflist));
	if (a == NULL)return NULL;
	long long int size = 0;
	char b[300] = {'\0'};
	hfencordlist_1(root, a, &size, num, b, 0);
	return a;
}
Node* buildTree(long long int size, Node **record, long long int *returnsize) {
	if (size < 2)return record[0];
	long long int top = size;
	long long int count1 = 0;
	Node *root = NULL;
	for (int i = 0; i < size - 1; i++) {
		int min = 0;
		for (int j = 0; j < top; j++) {
			if (record[j]->num < record[min]->num)min = j;
		}
		int secmin = (min == 0) ? 1 : 0;
		for (int j = 0; j < top; j++) {
			if (j == min)continue;
			if (record[j]->num < record[secmin]->num)secmin = j;
		}
		if (record[min]->rt == -1)record[min]->rt = count1++;
		if (record[secmin]->rt == -1)record[secmin]->rt = count1++;
		root = nodecreate('\0', record[min]->num + record[secmin]->num);
		root->lchild = record[min], root->rchild = record[secmin];
		if (root->rt == -1)root->rt = count1++;
		int temp1 = min > secmin ? secmin : min;
		int temp2 = min > secmin ? min : secmin;
		record[temp1] = root;
		record[temp2] = record[top - 1];
		top--;
	}
	*returnsize = count1;
	return root;
}
long long int CalculatedLength(hflist const *a, int const num) {
	long long int length = 0;
	for (int i = 0; i < num; i++) {
		length += (long long int)strlen(a[i].encoding) * (long long int)a[i].num;
	}
	return length;
}
chardata *statisticalTxt(char const *FileName, long long int *returnSize) {
	FILE *a;
	a = fopen(FileName, "r");
	if (a == NULL) {
		perror("文件打开失败");
		return NULL;
	}
	chardata *b = (chardata*)calloc(256, sizeof(chardata));
	if (b == NULL) {
		perror("数组b内存分配失败");
		fclose(a);
		return NULL;
	}
	char temp = '\0';
	*returnSize = 0;
	while (fscanf(a, "%c", &temp) != EOF) {
		if (b[(unsigned char)temp].num == 0) {
			b[(unsigned char)temp].data = temp;
			(*returnSize)++;
		}
		b[(unsigned char)temp].num++;
	}
	fclose(a);
	chardata *c = (chardata*)malloc(*returnSize * sizeof(chardata));
	if (c == NULL) {
		perror("数组c内存分配失败");
		fclose(a);
		free(b);
		return NULL;
	}
	for (int i = 0, j = 0; i < 256; i++) {
		if (b[i].num > 0) {
			c[j] = b[i];
			j++;
		}
	}
	qsort(c, *returnSize, sizeof(chardata), compare1);
	free(b);
	return c;
}
char *filenaming(char *fileExtension) {
	char s[10000] = {'\0'};
	while (1) {
		int flag = 0;
		printf("请输入期望文件名:");
		memset(s, '\0', sizeof(s));
		scanf("%9999s", s);
		for (int i = 0; s[i] != '\0'; i++) {
			if (s[i] == '\\' || s[i] == '/' || s[i] == ':' || s[i] == '*' ||
			s[i] == '?' || s[i] == '"' || s[i] == '<' || s[i] == '>' || s[i] == '|') {
				flag = 1;
				break;
			}
		}
		if (!flag)break;
		else printf("警告:该文件名不可用!\n");
	}
	char *a = (char*)malloc((strlen(s) +5) * sizeof(char));
	if (a == NULL) {
		perror("数组分配失败");
		return NULL;
	}
	strcpy(a, s);
	filerenamecheck(a, fileExtension);
	strcat(a, fileExtension);
	a[strlen(a)] = '\0';
	return a;
}
void compress_1(char const *FileName, hflist const *a, int const num, char *treefile) {
	FILE *b,*d;
	long long int length = CalculatedLength(a, num);
	hflist *list = (hflist*)malloc(256 * sizeof(hflist));
	for (int i = 0; i < num; i++) {
		int index = 0;
		index = (unsigned char)a[i].data;
		list[index] = a[i];
	}
	b = fopen(FileName, "r");
	char y[10] = ".dat";
	char *x = filenaming(y);
	d = fopen(x, "wb");
	int length1 = strlen(treefile);
	fwrite(&length1, sizeof(int), 1, d);
	fwrite(treefile, sizeof(char), length1, d);
	fwrite(&length, sizeof(long long int), 1, d);
	int bit = 0;
	char temp = '\0';
	char data = 0;
	while (fscanf(b, "%c", &temp) != EOF) {
		if (list[(unsigned char)temp].encoding == NULL)continue;
		int c = strlen(list[(unsigned char)temp].encoding);
		for (int i = 0; i < c; i++) {
			if (bit >= 8) {
				fputc(data, d);
				bit = 0;
				data = 0;
			}
			if (list[(unsigned char)temp].encoding[i] == '1') {
				data |= (1 << (7 - bit));
			}
			bit++;
		}
	}
	free(x);
	fputc(data, d);
	fclose(b);
	fclose(d);
}
Node *rebuildTree(char *treefile) {
	FILE *x;
	x = fopen(treefile, "r");
	int count1 = 0;
	fscanf(x, "%d\n", &count1);
	Node **record = (Node**)malloc((count1 + 1) * sizeof(Node*));
	for (int i = 0; i <= count1; i++) {
		record[i] = NULL;
	}
	for (int i = 0; i < count1; i++) {
		int a[3] = {0}, b[3] = {0}, c[3] = {0};
		fscanf(x, "%d %d %d %d %d %d %d %d %d\n", &a[0],
		       &a[1], &a[2], &b[0], &b[1], &b[2], &c[0], &c[1], &c[2]);
		if (record[a[0]] == NULL) {
			Node*temp = nodecreate((char)a[2], a[1]);
			temp->rt = a[0];
			record[a[0]] = temp;
		}
		if (b[0] != -1 && record[b[0]] == NULL) {
			Node*temp = nodecreate((char)b[2], b[1]);
			temp->rt = b[0];
			record[b[0]] = temp;
		}
		if (c[0] != -1 && record[c[0]] == NULL) {
			Node*temp = nodecreate((char)c[2], c[1]);
			temp->rt = c[0];
			record[c[0]] = temp;
		}
		if (b[0] != -1)record[a[0]]->lchild = record[b[0]];
		if (c[0] != -1)record[a[0]]->rchild = record[c[0]];
	}
	Node *root = record[count1 - 1];
	free(record);
	fclose(x);
	return root;
}
char *filePathcheck(char *a) {
	int length = strlen(a), j = 0;
	char *b = (char*)malloc(2 * length * sizeof(char));
	for (int i = 0; i < length; i++) {
		if (a[i] == '\\')b[j++] = a[i];
		b[j++] = a[i];
	}
	b[j] = '\0';
	return b;
}
char *name() {
	char s[10000] = {'\0'};
	scanf("%9999s", s);
	char *a = filePathcheck(s);
	return a;
}
void freeTree(Node *root) {
	if (root == NULL)return ;
	Node* l = root->lchild,*r = root->rchild;
	free(root);
	freeTree(l);
	freeTree(r);
}
int decode() {
	int flag = 0;
	char *Filename = name();
	FILE *a,*b;
	a = fopen(Filename, "rb");
	if (a == NULL) {
		perror("文件不存在");
		fclose(a);
		return 1;
	}
	char c[10] = ".txt";
	char *Filename1 = filenaming(c);
	if (Filename1 == NULL) {
		fclose(a);
		return 1;
	}
	b = fopen(Filename1, "w");
	if (b == NULL) {
		perror("文件创建失败");
		fclose(a);
		fclose(b);
		return 1;
	}
	int length1 = 0;
	long long int length = 0;
	fread(&length1, sizeof(int), 1, a);
	char *treefile = (char*)malloc((length1 + 1) * sizeof(char));
	fread(treefile, sizeof(char), length1, a);
	fread(&length, sizeof(long long int), 1, a);
	long long int size = (length + 7) / 8;
	char *data = (char*)malloc(size * sizeof(char));
	fread(data, sizeof(char), size, a);
	Node *root = rebuildTree(treefile),*current_node = NULL;
	if (root == NULL)flag = 1;
	current_node = root;
	for (int i = 0; i < size && flag != 1; i++) {
		int bit = 7;
		while (bit >= 0) {
			if (current_node->rchild == NULL) {
				fprintf(b, "%c", current_node->data);
				current_node = root;
			}
			if ((data[i] >> bit) & 1) {
				current_node = current_node->rchild;
			} else current_node = current_node->lchild;
			bit--;
		}
	}
	free(treefile);
	free(Filename1);
	free(data);
	fclose(a);
	fclose(b);
	freeTree(root);
	return flag;
}
void savehfulist(hflist *list, int num) {
	FILE *a;
	char b[100] = "HufCode";
	char c[10] = ".txt";
	filerenamecheck(b, c);
	strcat(b, ".txt");
	a = fopen(b, "w");
	for (int i = 0; i < num; i++) {
		fprintf(a, "%d %d %s\n", list[i].data, list[i].num, list[i].encoding);
	}
	fclose(a);
}
void freelist(hflist *a, int num) {
	for (int i = 0; i < num; i++) {
		free(a[i].encoding);
	}
}
int compress_main() {
	long long int num = 0, count1 = 0;
	char *filename = name();
	chardata *b = statisticalTxt(filename, &num);
	if (b == NULL)return 1;
	Node *root = NULL;
	Node **record = (Node**)malloc(num * sizeof(Node*));
	if (record == NULL) {
		perror("数组record内存分配失败");
		free(b);
		return 1;
	}
	for (int i = 0; i < num; i++) {
		Node *temp = nodecreate(b[i].data, b[i].num);
		record[i] = temp;
	}
	root = buildTree(num, record, &count1);
	hflist *c = hfencordlist(root, num);
	if (c == NULL) {
		free(b);
		return 1;
	}
	char treefile[100] = {'\0'};
	savehfuTree(root, count1, treefile);
	compress_1(filename, c, num, treefile);
	savehfulist(c, num);
	free(b);
	free(filename);
	freeTree(root);
	free(record);
	freelist(c, num);
	free(c);
	return 0;
}
int choose() {
	printf("请选择:");
	char a[10000] = {'\0'};
	scanf("%9999s", a);
	int length = strlen(a);
	if (length == 1) {
		if (a[0] == 'A' || a[0] == 'a')return 1;
		if (a[0] == 'B' || a[0] == 'b')return 2;
		if (a[0] == 'C' || a[0] == 'c')return 3;
		if (a[0] == 'D' || a[0] == 'd')return 4;
		if (a[0] == 'E' || a[0] == 'e')return 5;
	}
	return -1;
}
void print_main() {
	printf("%*s####文本文件压缩####\n", 10, " ");
	printf("%*sA.压缩文件\n", 14, " ");
	printf("%*sB.解压文件\n", 14, " ");
	printf("%*sC.统计字符频率\n", 14, " ");
	printf("%*sD.退出\n", 14, " ");
}
void object_print() {
	printf("请选择排序对象:\n");
	printf("%*sA.频率\n", 14, " ");
	printf("%*sB.字符ASCII值\n", 14, " ");
	printf("%*sC.返回\n", 14, " ");
}
void SortOrder() {
	printf("请选择排序顺序:\n");
	printf("%*sA.升序\n", 14, " ");
	printf("%*sB.降序\n", 14, " ");
	printf("%*sC.返回\n", 14, " ");
}
void chardataHandle(chardata **a, int object, int order, int num) {
	if (object == 1 && order == 1) {
		qsort(*a, num, sizeof(chardata), compare1);
	}
	if (object == 2 && order == 1) {
		qsort(*a, num, sizeof(chardata), compare2);
	}
	if (object == 1 && order == 2) {
		qsort(*a, num, sizeof(chardata), compare3);
	}
	if (object == 2 && order == 2) {
		qsort(*a, num, sizeof(chardata), compare4);
	}
}
int reasonableJudgment(int max) {
	int a = 0;
	while (1) {
		printf("请输入位序:");
		a = enterNumbers();
		if (a <= 0 || a > max)printf("数据不合理,请重新输入!\n");
		else break;
	}
	return a;
}
int selection(void a(), int *data) {
	while (1) {
		a();
		int b = choose();
		if (b == 1) {
			*data = 1;
			break;
		} else if (b == 2) {
			*data = 2;
			break;
		} else if (b == 3)return 1;
		else printf("请输入有效选择!\n");
	}
	return 0;
}
int BasicSelection(int *object, int *order) {
	while (1) {
		int a = selection(SortOrder, order);
		if (a == 1)return 1;
		int b = selection(object_print, object);
		if (b != 1)break;
	}
	return 0;
}
int sequence(chardata *a, int flag, int num, int way) {
	int object = 1, order = 1;
	if (flag == 1 && BasicSelection(&object, &order))return 1;
	chardataHandle(&a, object, order, num);
	int c = reasonableJudgment(num);
	if (way == 1)printf("顺序第%d个字符是%c。\n", c, a[c - 1].data);
	else printf("逆序第%d个字符是%c。\n", c, a[num - c].data);
	return 0;
}
void charQuery_print() {
	printf("请选择查询顺序:\n");
	printf("%*sA.顺序(默认选择)\n", 14, " ");
	printf("%*sB.顺序\n", 14, " ");
	printf("%*sC.逆序(默认选择)\n", 14, " ");
	printf("%*sD.逆序\n", 14, " ");
	printf("%*sE.返回\n", 14, " ");
}
int charQuery(chardata *a, int num) {
	while (1) {
		charQuery_print();
		int b = choose();
		if (b == 1) {
			if (!sequence(a, 0, num, 1))break;
		} else if (b == 2) {
			if (!sequence(a, 1, num, 1))break;
		} else if (b == 3) {
			if (!sequence(a, 0, num, 2))break;
		} else if (b == 4) {
			if (!sequence(a, 1, num, 2))break;
		} else if (b == 5)return 1;
		else printf("请输入有效选择!\n");
	}
	return 0;
}
void intervalQuery_print() {
	printf("请选择查询对象:\n");
	printf("%*sA.字符频率区间\n", 14, " ");
	printf("%*sB.字符ASCII值区间(默认选择)\n", 14, " ");
	printf("%*sC.返回\n", 14, " ");
}
int *findinterval(int *returnsize, chardata *a, int num, int frist, int last, int flag) {
	int *b = (int*)malloc(num * sizeof(int));
	*returnsize = 0;
	for (int i = 0; i < num; i++) {
		if (flag == 1 && a[i].num <= last && a[i].num >= frist)b[(*returnsize)++] = i;
		if (flag == 2 && a[i].data <= last && a[i].data >= frist)b[(*returnsize)++] = i;
	}
	return b;
}
int interval(chardata *a, int num, int b) {
	int frist = 0, last = 0;
	while (1) {
		printf("请输入区间起始位置:");
		frist = enterNumbers();
		if (frist > 0 && frist < num)break;
		else printf("数据不合理,请重新输入!\n");
	}
	while (1) {
		printf("请输入区间末尾位置:");
		last = enterNumbers();
		if (((b == 1 && last <= a[0].num) || (b == 2 && last <= 256)) && last > frist)break;
		else printf("数据不合理,请重新输入!\n");
	}
	int size = 0;
	int *c = findinterval(&size, a, num, frist, last, b);
	if (size == 0)printf("该区间无符合值!\n");
	else {
		if (b == 1)printf("字符频率从%d到%d有:\n", frist, last);
		else printf("字符ASCII值从%d到%d有:\n", frist, last);
		for (int i = 0; i < size; i++) {
			printf("%*s", 16, " ");
			printf("%c %d\n", a[c[i]].data, a[c[i]].num);
		}
		printf("\n");
	}
	free(c);
	return 0;
}
int intervalQuery(chardata *a, int num) {
	qsort(a, num, sizeof(chardata), compare3);
	while (1) {
		intervalQuery_print();
		int b = choose();
		if (b > 0 && b < 3) {
			if (!interval(a, num, b))break;
		} else if (b == 3)return 1;
		else printf("请输入有效选择!\n");
	}
	return 0;
}
void inputprint(chardata *a, int frist, int last, int num) {
	for (int i = frist; i < last && i < num; i++) {
		printf("%*s", 10, " ");
		if (a[i].data != '\n')printf("%c%8d\n", a[i].data, a[i].num);
		else printf("\\n%7d\n", a[i].num);
	}
}
void pagprint(chardata *a, int pag, int num, int pagnum) {
	int count1 = (pag - 1) * pagnum;
	inputprint(a, count1, count1 + pagnum, num);
	if (pag != 1)printf("上一页");
	else printf("%*s", 5, " ");
	printf("%*s", 17, " ");
	if (pag * pagnum < num)printf("下一页");
	printf("\n");
}
void pagQueryprintremind() {
	printf("%*s输入提醒:\n", 18, " ");
	printf("A.上一页");
	printf("%*sB.下一页", 8, " ");
	printf("%*sC.返回\n", 8, " ");
}
int pagQueryprint(int num) {
	int a = 0;
	while (1) {
		printf("请输入每页展示数量:");
		a = enterNumbers();
		if (a <= num && a > 0)break;
		else printf("数据不合理,请重新输入!\n");
	}
	pagQueryprintremind();
	return a;
}

int pagQuery(chardata *a, int num) {
	int b = pagQueryprint(num);
	int d = 1;
	pagprint(a, 1, num, b);
	while (1) {
		int c = choose(), flag = 0;
		if (c == 1 && d - 1 >= 1)d--;
		else if (c == 2 && num - d * b > 0)d++;
		else if (c == 3)return 0;
		else flag = 1;
		if (!flag)pagprint(a, d, num, b);
		else {
			if (num - d * b <= 0 && c == 2)printf("已经到最后一页了!\n");
			else if (d == 1 && c == 1)printf("已经到第一页了!\n");
			else {
				printf("请输入有效选择!\n");
				pagQueryprintremind();
			}
		}
	}
	return 0;
}
int allQuery(chardata *a, int num) {
	int object = 1, order = 1;
	if (BasicSelection(&object, &order))return 1;
	chardataHandle(&a, object, order, num);
	inputprint(a, 0, num, num);
	return 0;
}
void statistics_print() {
	printf("请选择查询方式:\n");
	printf("%*sA.单字符查询\n", 14, " ");
	printf("%*sB.区间查询\n", 14, " ");
	printf("%*sC.分页查询\n", 14, " ");
	printf("%*sD.查询全部\n", 14, " ");
	printf("%*sE.返回\n", 14, " ");
}
int statistics_main() {
	char *a = name();
	long long int num = 0;
	chardata *b = statisticalTxt(a, &num);
	if (b == NULL)return -1;
	while (1) {
		statistics_print();
		int c = choose();
		if (c == 1)charQuery(b, num);
		else if (c == 2)intervalQuery(b, num);
		else if (c == 3)pagQuery(b, num);
		else if (c == 4)allQuery(b, num);
		else if (c == 5)return 1;
		else printf("请输入有效选择!\n");
	}
	free(a);
	return 0;
}
int main() {
	while (1) {
		print_main();
		int a = choose();
		if (a != -1 && a != 4)printf("请输入文件名或文件路径:");
		if (a == 1) {
			if (!compress_main())printf("成功!\n");
			else printf("失败!\n");
		} else if (a == 2) {
			if (!decode())printf("成功!\n");
			else printf("失败!\n");
		} else if (a == 3) {
			if (statistics_main() != -1)printf("成功!\n");
			else printf("失败!\n");
		} else if (a == 4)break;
		else printf("请输入有效选择!\n");
	}
	return 0;
}

注意:

 1.该程序对非英文文本文件的解压存在解压失败的可能性,但大部分时候不会出现解压失败的情况。

2.对于输入,不支持输入非英文字符!

3.C语言版对错误处理不如EasyX版完善。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值