哈夫曼永远的神
哈夫曼编码译码终于要完结了。译码和源文件大小一致了,把换行符也加上去了。结。
区别:两个源文件,一个是自设权重,另外一个是根据字符出现的频率当做权重。
主函数的后缀是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;
上半部分介绍了哈夫曼的中序遍历等