哈夫曼树的创建和编码和译码和压缩(根据编码文件进行译码),压缩等操作c语言

哈夫曼永远的神

哈夫曼编码译码终于要完结了。译码和源文件大小一致了,把换行符也加上去了。结。

区别:两个源文件,一个是自设权重,另外一个是根据字符出现的频率当做权重。

主函数的后缀是c++的后缀 .cpp

以频率为权重的运行结果如下

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

以频率为权重的哈夫曼树源文件:

#include "优先权队列.h"
#include "哈夫曼的stack.h"
void Create(BinaryTree* bt)
{
	bt->root = NULL;
}
HFMTNode* NewBTNode(char Element, int w, HFMTNode* lC, HFMTNode* rC)
{
	HFMTNode* p = (HFMTNode*)malloc(sizeof(HFMTNode));
	p->Element = Element;
	p->w = w;
	p->lChild = lC;
	p->rChild = rC;
	p->judge = 0;
	return p;
}
void MakeTree(BinaryTree* bt,char element, int w, BinaryTree* left, BinaryTree* right)
{
	if (left == NULL || right == NULL)
		return;
	else
	{
		bt->root = NewBTNode(element, w,left->root, right->root);
		left->root = right->root = NULL;
	}
}

//哈夫曼先序遍历
void PreOrder(HFMTNode* t)
{
	if (!t)
		return;
	printf("%d ", t->w);
	PreOrder(t->lChild);
	PreOrder(t->rChild);
}
void PreOrderHFMTree(BinaryTree* bt)
{
	printf("\n先序遍历哈夫曼树的结果为:\n");
	PreOrder(bt->root);
}
// 哈夫曼中序遍历
void InOrder(HFMTNode* t)
{
	if (!t)
		return;
	InOrder(t->lChild);
	printf("%d ", t->w);
	InOrder(t->rChild);
}
void InOrderHFMTree(BinaryTree* bt)
{
	printf("\n中序遍历哈夫曼树的结果为:\n");
	InOrder(bt->root);
}
void CreateHFMTree(BinaryTree* bt,int w[], int m)
{
	PriorityQueue PQ;
	BinaryTree x, h, g;
	Create(&x);
	Create(&h);
	Create(&g);
	CreatePQ(&PQ, m);
	for (int i = 0; i < m; i++)
	{
		if (w[i] != 0)
		{
			MakeTree(&x, char(i), w[i], &h, &g);
			Append(&PQ, x.root);
		}
	}
	printf("原森林:\n");
	for (int i = 0; i < PQ.n; i++)
	{
		printf("%d  ", PQ.elements[i].w);
	}
	while (PQ.n > 1)
	{
		HFMTNode* X = NewBTNode(' ', 0, NULL, NULL);
		HFMTNode* Y = NewBTNode(' ', 0, NULL, NULL);
		HFMTNode* Z = NewBTNode(' ', 0, NULL, NULL);
		Serve(&PQ, X);
		Serve(&PQ, Y);
		if (X->w < Y->w)
		{
			Z->w = X->w + Y->w;
			Z->lChild = X;
			Z->rChild = Y;
			Z->Element = ' ';
			Append(&PQ, Z);
		}
		else
		{
			Z->w = X->w + Y->w;
			Z->lChild = Y;
			Z->rChild = X;
			Append(&PQ, Z);
		}
	}
	*bt->root = PQ.elements[0];
}


//进行哈夫曼编码
HFMTNode* HFMBMFirst(BinaryTree* tree, Stack* S, char* temp, int* index, int length, int* frequency)
{
	int fre = *frequency;
	int k = *index;
	HFMTNode* p = tree->root;
	while (p->lChild != NULL)
	{
		stackPush(S, p);
		temp[k++] = '0';
		p = p->lChild;
	}
	temp[k] = '\0';
	*index = k;
	fre++;
	*frequency = fre;
	return p;
}
HFMTNode* HFMBMNext(HFMTNode* current, Stack* S, char* temp, int* index, int length, int* frequency)
{
	int fre = *frequency;
	int k = *index;
	HFMTNode * p = current;
	HFMTNode* again;
	BinaryTree h, i, j;
	Create(&h);
	Create(&i);
	Create(&j);
	MakeTree(&h, 'H',0, &i, &j);
	again = h.root;
	if (p->rChild && current->judge != 1 && (fre < length))
	{
		p->judge = 1;
		stackPush(S, p);
		p = p->rChild;
		temp[k++] = '1';
		while (p->lChild != NULL)
		{
			stackPush(S, p);
			p = p->lChild;
			temp[k++] = '0';
		}
		temp[k] = '\0';
		*index = k;
		fre++;
		*frequency = fre;
		return p;
	}
	else if ((!stackIsEmpty(S)) && (fre < length))
	{
		stackTop(S, again);
		stackPop(S);
		if ((again->rChild) && (again->judge != 1) && (fre < length))
		{
			temp[--k] = '\0';
			again->judge = 1;
			stackPush(S, again);
			again = again->rChild;
			temp[k++] = '1';
			while (again->lChild != NULL)
			{
				stackPush(S, again);
				again = again->lChild;
				temp[k++] = '0';
			}
			temp[k] = '\0';
			fre++;
			*frequency = fre;
			*index = k;
			return again;
		}
		else if ((again->rChild) && (again->judge == 1) && (fre < length))
		{
			while (again->judge == 1&&(fre<length))
			{
				stackTop(S, again);
				stackPop(S);
				temp[--k] = '\0';
			}
			if ((again->rChild) && (again->judge != 1) && (fre < length))
			{
				temp[--k] = '\0';
				again->judge = 1;
				stackPush(S, again);
				again = again->rChild;
				temp[k++] = '1';
				while (again->lChild != NULL)
				{
					stackPush(S, again);
					again = again->lChild;
					temp[k++] = '0';
				}
			}
			temp[k] = '\0';
			fre++;
			*frequency = fre;
			*index = k;
			return again;
		}
	}
	else
	{
		p = current;
		p->w = -1;
		return p;
	}
}

void HFMBTNodeAll(BinaryTree* bt, int QZ[], int length, char BMofchar[128][20])
{
	int m=0;
	int index = 0;
	char temp[400] = "";
	int frequency = 0;
	Stack S;
	stackCreate(&S, 400);
	if (!bt->root)
	{
		printf("此二叉树为空!");
		return;
	}
	HFMTNode* current = HFMBMFirst(bt,&S,temp,&index,length,&frequency);
	while (current->w != -1)
	{
		for (int i = 0; i < 128; i++)
		{
			if ((current->w == QZ[i]) && (current->Element == char(i)))
			{
				printf("序号为%d的%c的编码是:",i, i);
				puts(temp);
				printf("其权重为%d\n\n", current->w);
				for (int j = 0; temp[j] != '\0'; j++)
				{
					BMofchar[i][j] = temp[j];
				}
			}
		}
		current = HFMBMNext(current, &S, temp, &index, length, &frequency);
		printf("\n%d ", m++);
	}
	printf("编码完成!");
}
void NumOfChar(int QZ[128])
{
	char c;
	FILE* fp;
	fopen_s(&fp, "C:\\Users\\HP\\Desktop\\数据结构实验报告\\text.txt", "r");
	if (fp == 0)
	{
		printf("file error\n");
		exit(1);
	}
	c=fgetc(fp);
	while (!feof(fp))
	{
		QZ[c]++;
		c = fgetc(fp);
	}
	fclose(fp);
	//统计完毕
}
void save_to_secret(char BMofchar[128][20])
{
	int num = 0;
	FILE* fp1,*fp2;
	char temp1[16] = "";
	char str[500] = "";
	fopen_s(&fp1, "C:\\Users\\HP\\Desktop\\数据结构实验报告\\text.txt", "r");
	fopen_s(&fp2, "C:\\Users\\HP\\Desktop\\数据结构实验报告\\secret.txt", "a+");
	if (fp1 == 0)
	{
		printf("file error!!\n");
		exit(1);
	}
	while (!feof(fp1))
	{
		fgets(str, 300, fp1);
		for (int i = 0; str[i] != '\0'; i++)
		{
			temp1[0] = str[i];
			int direction = int(temp1[0]);
			for (int num = 0; num < 128; num++)
			{
				if (num == direction)
				{
					fputs(BMofchar[num], fp2);
					//printf("%d ", direction);
				}
			}
		}
	}
	//puts(str);
	fclose(fp1);
	fclose(fp2);
	printf("编码已完成并保存到secret.txt\n");
}

void secret_back_to_text(char BMofchar[128][20])
{
	FILE* fp2, *fp3;
	//实行哈夫曼译码算法如下:
	fopen_s(&fp2, "C:\\Users\\HP\\Desktop\\数据结构实验报告\\secret.txt", "r");
	fopen_s(&fp3, "C:\\Users\\HP\\Desktop\\数据结构实验报告\\re_text.txt", "a+");
	if (fp2 == 0 || fp3 == 0)
	{
		printf("file error\n");
		exit(1);
	}
	char transfer[400] = "";
	char temp2[20] = "";
	int Y = 0;
	char thischar[3] = "";
	fgets(transfer, 400, fp2);
	for (int i = 0; !feof(fp2); i++)
	{
		int judge = 1;
		temp2[Y++] = transfer[i];
		temp2[Y] = '\0';
		//每次添加一个字符都要判断temp2是否和BMofchar中的元素是否相等
		for (int num = 0; num < 128&&judge; num++)
		{
			if ((strcmp(temp2, BMofchar[num]) == 0)&&judge)
			{
				thischar[0] = num;
				thischar[1] = '\0';
				//printf("%s", thischar);
				fputs(thischar, fp3);
				Y = 0;
				judge = 0;;
			}
		}
		if (transfer[i + 1] == '\0')
		{
			fgets(transfer, 400, fp2);
			i = -1;
			//i = 0;
		}
	}
	for (int i = 0; transfer[i] != '\0'; i++)
	{
		temp2[Y++] = transfer[i];
		temp2[Y] = '\0';
		for (int num = 0; num < 128; num++)
		{
			if (strcmp(temp2, BMofchar[num]) == 0)
			{
				thischar[0] = num;
				thischar[1] = '\0';
				fputs(thischar, fp3);
				Y = 0;
			}
		}
	}
	printf("译码已完成,译码已放入re_text.txt中\n");
	fclose(fp2);
	fclose(fp3);
}

void otc_back_to_text(char BMofchar[128][20])
{
	FILE* fp4,*fp5;
	fopen_s(&fp4, "C:\\Users\\HP\\Desktop\\数据结构实验报告\\secret_otc.txt", "r");
	fopen_s(&fp5, "C:\\Users\\HP\\Desktop\\数据结构实验报告\\otc_to_text.txt","a+");
	if (fp4 == 0||fp5==0)
	{
		printf("\nfile error!!\n");
		exit(1);
	}
	char temp[8] = "0000000";
	char c = ' ';
	char str[300] = "";
	fgets(str,300,fp4);
	puts(str);
	for (int i = 0; !feof(fp4); i++)
	{
		c = str[i];
		printf("%c", c);
		if (str[i + 1] == '\0')
		{
			fgets(str, 300, fp4);
			i = 0;
		}
	}
	printf("\n解压成功!!\n");
}

void to_smaller()
{
	FILE* fp4, * fp2;
	char temp3[32] = "";
	char rows[300] = "";
	fopen_s(&fp2, "C:\\Users\\HP\\Desktop\\数据结构实验报告\\secret.txt", "r");
	fopen_s(&fp4, "C:\\Users\\HP\\Desktop\\数据结构实验报告\\secret_otc.txt", "a+");
	if (fp2 == 0 || fp4 == 0)
	{
		printf("\nfile error!!\n");
		exit(1);
	}
	fgets(rows, 300, fp2);
	int X = 0, Z = 0;
	char c = '1';
	while (!feof(fp2))
	{
		temp3[X++] = rows[Z++];
		if (X == 7)
		{
			unsigned char yasuo = 0;
			int shuzi = 0;
			for (int h = 6; h >= 0; h--)
			{
				shuzi += (int(temp3[h]) - 48) * pow(2, h);
			}
			if (shuzi <= 127)
			{
				yasuo = (unsigned char)(shuzi);
				fputc(yasuo, fp4);
			}
			if (shuzi > 127)
			{
				yasuo = (unsigned char)(shuzi - 256);
				fputc(yasuo, fp4);
			}
			X = 0;
		}
		if (rows[Z] == '\0')
		{
			fgets(rows, 300, fp2);
			Z = 0;
		}
	}
	while (rows[Z] != '\0')
	{
		temp3[X++] = rows[Z++];
		if (X == 7)
		{
			unsigned char yasuo = 0;
			int shuzi = 0;
			for (int h = 6; h >= 0; h--)
			{
				shuzi += (int(temp3[h]) - 48) * pow(2, h);
			}
			if (shuzi <= 127)
			{
				yasuo = (unsigned char)(shuzi);
				fputc(yasuo, fp4);
			}
			if (shuzi > 127)
			{
				yasuo = (unsigned char)(shuzi - 256);
				fputc(yasuo, fp4);
			}
			X = 0;
		}
	}
	printf("\n压缩完成!!!\n");
}


void main()
{
	BinaryTree bt, h, i;
	char BMofchar[128][20] = {};
	int length=0;
	Create(&bt);
	Create(&h);
	Create(&i);
	MakeTree(&bt, 0, ' ', &h, &i);
	int QZ[128] = { 0 };
	NumOfChar(QZ);
	CreateHFMTree(&bt, QZ,128);
	PreOrderHFMTree(&bt);
	InOrderHFMTree(&bt);
	printf("\nlength的长度为%d\n", length);
	printf("\n\n");
	for (int i = 0; i < 128; i++)
	{
		if (QZ[i] != 0)
			length++;
	}
	HFMBTNodeAll(&bt, QZ,length, BMofchar); //哈夫曼编码完成
	save_to_secret(BMofchar);  //转换为二进制存储到文件
	to_smaller();  //进行转换压缩
	secret_back_to_text(BMofchar);  //回到原文
	printf("\n");
	//otc_back_to_text(BMofchar);
}

完全版创建文件来存放编码和存放译码(现已实现换行符功能)

自设权重的运行结果

在这里插入图片描述

在这里插入图片描述

优先权队列.h:

#pragma once
#include "HFMBTNODE.h"
typedef struct priorityQueue
{
	HFMTNode* elements;
	int n;
	int maxSize;
}PriorityQueue;
void AdjustUp(HFMTNode heap[], int current)
{
	int p = current;
	HFMTNode temp;
	while (p > 0)
	{
		if (heap[p].w < heap[(p - 1) / 2].w)
		{
			temp = heap[p];
			heap[p] = heap[(p - 1) / 2];
			heap[(p - 1) / 2] = temp;
			p = (p - 1) / 2;  //将p向上移动至当前考查元素的双亲节点位置
		}
		else  //若p指向的元素不小于其双亲节点,则调整完毕
			break;
	}
}
void AdjustDown(HFMTNode heap[], int current, int border)
{
	int p = current;
	int minChild;
	HFMTNode temp;
	while (2 * p + 1 <= border)
	{
		if ((2 * p + 2 <= border) && (heap[2 * p + 1].w > heap[2 * p + 2].w))
		{
			minChild = 2 * p + 2;
		}
		else
		{
			minChild = 2 * p + 1;
		}
		if (heap[p].w <= heap[minChild].w)
		{
			break;
		}
		else
		{
			temp = heap[p];
			heap[p] = heap[minChild];
			heap[minChild] = temp;
			p = minChild;
		}
	}
}

//创建一个空的优先权队列
void CreatePQ(PriorityQueue* PQ, int mSize)
{
	PQ->maxSize = mSize;
	PQ->n = 0;
	PQ->elements = (HFMTNode *)malloc(mSize * sizeof(HFMTNode));
}

// 销毁一个优先权队列,释放其占用的空间
void Destory(PriorityQueue* PQ)
{
	free(PQ->elements);
	PQ->n = 0;
	PQ->maxSize = 0;
}

//判断优先权队列是否为空
BOOL IsEmpty(PriorityQueue* PQ)
{
	if (PQ->n == 0)
		return TRUE;
	else
		return FALSE;
}

//判断优先权队列是否已满
BOOL IsFull(PriorityQueue* PQ)
{
	if (PQ->n == PQ->maxSize)
		return TRUE;
	else
		return FALSE;
}

//获取当前优先权队列中的元素的数量
int Size(PriorityQueue* PQ)
{
	return PQ->n;
}

//在优先权队列中增加一个新元素x
void Append(PriorityQueue* PQ, HFMTNode *x)
{
	if (IsFull(PQ))
		return;
	PQ->elements[PQ->n] = *x;
	PQ->n++;
	AdjustUp(PQ->elements, PQ->n - 1);
}

//取出优先级最高的元素,利用参数x返回,并在优先权队列中删除该元素
void Serve(PriorityQueue* PQ, HFMTNode* x)
{
	if (IsEmpty(PQ))
		return;
	*x = PQ->elements[0];
	PQ->n--;
	PQ->elements[0] = PQ->elements[PQ->n];
	AdjustDown(PQ->elements, 0, PQ->n - 1);
}

哈夫曼的stack.h:

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include "HFMBTNODE.h"
#define STACKSIZE 100
typedef struct Stack
{
	int top;
	int maxSize;
	HFMTNode* element;
}Stack;
void stackCreate(Stack* S, int mSize)
{
	S->maxSize = mSize;
	S->element = (HFMTNode*)malloc(sizeof(HFMTNode) * mSize);
	S->top = -1;
}
void stackDestory(Stack* S)
{
	S->maxSize = 0;
	S->top = -1;
	free(S->element);
}
BOOL stackIsEmpty(Stack* S)
{
	return S->top == -1;
}
BOOL stackIsFULL(Stack* S)
{
	return S->top == S->maxSize - 1;
}
BOOL stackTop(Stack* S, HFMTNode* x)
{
	if (stackIsEmpty(S))
	{
		return FALSE;
	}
	*x = S->element[S->top];
	return TRUE;
}
BOOL stackPush(Stack* S, HFMTNode *x)
{
	if (stackIsFULL(S))
		return FALSE;
	S->top++;
	S->element[S->top] = *x;
	return TRUE;
}
BOOL stackPop(Stack* S)
{
	if (stackIsEmpty(S))
		return FALSE;
	S->top--;
	return TRUE;
}
void Clear(Stack* S)
{
	S->top = 1;
}

HFMBTNODE.h:

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<string>
typedef int ElemType;
typedef int BOOL;
#define TRUE 1
#define FALSE 0
typedef struct hfmTNode
{
	int judge;
	char Element;
	int w;  //权重
	struct hfmTNode* lChild; //左孩子
	struct hfmTNode* rChild; //右孩子
}HFMTNode;
typedef struct binarytree
{
	HFMTNode* root;
}BinaryTree;

上半部分介绍了哈夫曼的中序遍历等

哈夫曼编码已完成,译码已完成,更新完毕,由此结束。

  • 9
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
哈夫曼编码是一种基于字符出现频率的压缩算法,它可以将出现频率高的字符用较短的编码表示,而出现频率低的字符用较长的编码表示,从而达到压缩文件的目的。下面是C语言文件压缩哈夫曼编码译码的方法: 1. 哈夫曼编码 首先需要统计文件中每个字符出现的频率,然后根据频率构建哈夫曼树,最后根据哈夫曼树生成每个字符的编码表。具体步骤如下: - 统计文件中每个字符出现的频率,可以使用一个数组来记录每个字符出现的次数。 - 根据字符频率构建哈夫曼树,可以使用优先队列来实现。将每个字符及其频率作为一个节点,将所有节点加入优先队列中,每次取出频率最小的两个节点,合并成一个新节点,将新节点加入优先队列中,直到队列中只剩下一个节点,即为哈夫曼树的根节点。 - 根据哈夫曼树生成每个字符的编码表,可以使用递归的方法遍历哈夫曼树,对于每个叶子节点,记录其对应字符的编码编码可以用0和1表示,左子树为0,右子树为1。 2. 哈夫曼译码 哈夫曼译码是将压缩后的文件压缩成原始文件的过程,需要使用哈夫曼树编码表来实现。具体步骤如下: - 根据压缩文件生成哈夫曼树,可以将压缩文件的前几个字节作为哈夫曼树的结构,具体格式可以自行定义。 - 根据哈夫曼树编码表对压缩文件进行译码,从压缩文件中读取一个比特位,根据比特位在哈夫曼树上遍历,直到遍历到叶子节点,即为一个字符,将该字符写入解压缩文件中,继续读取下一个比特位,直到压缩文件读取完毕。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值