#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
typedef char ElemType;
typedef struct HTNODE{
ElemType data;//数据域
struct HTNODE* lchild;//左孩子
struct HTNODE* rchild;//右孩子
}HtNode,*HtNodePtr;//哈夫曼树节点结构体
typedef struct TREE{
HtNodePtr root;//哈夫曼树的根节点
}HtTree,*HtTreePtr;
typedef struct HTTABLE{
ElemType data;
char* s;//存储数据data的编码
struct HTTABLELIST* next;
}HtTable,*HtTablePtr;//哈夫曼表的链表的节点
typedef struct HTTABLELIST{
struct HTTABLE* head;
struct HTTABLE* tail;
}HtTaLi,*HtTaLiPtr;//哈夫曼表的链表
typedef struct NODE{
HtNodePtr data;//树节点
int num;//哈夫曼树节点的权值
struct NODE* next;
}Node,*NodePtr;//链表节点
typedef struct LIST{
NodePtr head;//链表头结点
int size;//链表长度
}List,*ListPtr;//链表
ListPtr Init();//初始化并创建链表
HtTaLiPtr InitTable();//初始化哈夫曼表
void Insert(ListPtr L, char ch, int num);//在链表中插入权值为num,字符为ch的节点,并且它的插入是按权值从大到小的顺序插入的
NodePtr GetFirst(ListPtr L);//得到并删除链表中第一个元素
void InsertNode(ListPtr L, NodePtr node);//按照权值的大小将节点node插入链表中
HtNodePtr CreatTree(ListPtr L);//建立哈夫曼树
void TraverseTree(HtNodePtr Ht, char code[], int k, HtTaLiPtr HtTableList);
void CreatTable(HtTreePtr tree);//创建哈夫曼表
void EnCode(HtTaLiPtr HtTableList);//编码
void DeCode(HtTreePtr tree);//解码
void PrintTree(HtNodePtr Ht, char* s, char* s1, FILE* fp);//先序遍历,凹入形式打印哈夫曼树
void WriteTree(HtTreePtr tree);//把哈夫曼树写到文件中
void TreaseWrite(HtNodePtr Ht, FILE* fp);//以先序遍历的方式把哈夫曼树写到文件中
void PrintCodeFile();// 将文件CodeFile显示在终端上,每行 50 个代码。同时将此字符形式的编码文件写入文件 CodePrin 中。
int main()
{
ListPtr L = Init();//建立并初始化链表
puts("读取data.txt数据");
char p1[4] = { '\0' };
char p2[4] = { '\0' };
FILE* fp;
if ((fp = fopen("C://Users/17681/Desktop/data.txt", "r")) == NULL)
{
puts("打开data.txt失败!");
}
Insert(L, ' ', 186);
printf("%c %d ", ' ', 186);
while (!feof(fp))
{
fscanf(fp, "%s", p1);
fscanf(fp, "%s", p2);
printf(" %s %d ", p1,atoi(p2));
Insert(L, p1[0], atoi(p2));
}
fclose(fp);
//int n;
//ListPtr L = Init();//建立并初始化链表
//puts("请输入字符集大小(为了方便规定不大于256)");
//scanf("%d", &n);
//for (int i = 0; i < n; i++)
//{
// printf("请输入第%d个字符\n", i + 1);
// char ch;
// fflush(stdin);
// scanf("%c", &ch);
// printf("请输入它的权值\n");
// int num;
// scanf("%d", &num);
// Insert(L, ch, num);
//}
HtTreePtr tree = (HtTreePtr)malloc(sizeof(HtTree));
tree->root = CreatTree(L);
WriteTree(tree);
HtTaLiPtr HtTableList = InitTable();
CreatTable(tree, HtTableList);
EnCode(HtTableList);
DeCode(tree);
puts("打印代码文件");
PrintCodeFile();
puts("先序遍历,凹入形式打印哈夫曼树叶子节点");
char s[100] = {'\0'};
FILE* fp1;
if ((fp1 = fopen("C://Users/17681/Desktop/TreePrint.txt", "w")) == NULL)
{
puts("CodeFile.txt文件打开失败!");
}
PrintTree(tree->root, s, s, fp1);
fclose(fp1);
system("pause");
return 0;
}
ListPtr Init()
{
ListPtr L = (ListPtr)malloc(sizeof(List));
L->head = (NodePtr)malloc(sizeof(Node));
L->head->next = NULL;
L->size = 0;
return L;
}
HtTaLiPtr InitTable()
{
HtTaLiPtr HtTableList = (HtTaLiPtr)malloc(sizeof(HtTaLi));
HtTableList->head = HtTableList->tail = (HtTablePtr)malloc(sizeof(HtTable));
HtTableList->tail->next = NULL;
return HtTableList;
}
void Insert(ListPtr L, char ch, int num)
{
NodePtr newnode = (NodePtr)malloc(sizeof(Node));
newnode->num = num;
newnode->data = (HtNodePtr)malloc(sizeof(HtNode));
newnode->data->data = ch;
newnode->data->lchild = NULL;
newnode->data->rchild = NULL;
NodePtr tempnode = L->head;
while (tempnode->next != NULL)
{
if (newnode->num >= tempnode->next->num)
{
tempnode = tempnode->next;
}
else
{
break;
}
}
newnode->next = tempnode->next;
tempnode->next = newnode;
L->size++;
}
NodePtr GetFirst(ListPtr L)
{
NodePtr node = L->head->next;
L->head = L->head->next;
L->size--;
return node;
}
void InsertNode(ListPtr L, NodePtr node)
{
NodePtr tempnode = L->head;
while (tempnode->next != NULL)
{
if (node->num >= tempnode->next->num)
{
tempnode = tempnode->next;
}
else
{
break;
}
}
node->next = tempnode->next;
tempnode->next = node;
L->size++;
}
HtNodePtr CreatTree(ListPtr L)
{
NodePtr node1;
NodePtr node2;
NodePtr newnode;
while (L->size > 1)
{
node1 = GetFirst(L);
node2 = GetFirst(L);
newnode = (NodePtr)malloc(sizeof(Node));
newnode->num = node1->num + node2->num;
newnode->data = (HtNodePtr)malloc(sizeof(HtNode));
newnode->data->data = '#';
newnode->data->lchild = node1->data;
newnode->data->rchild = node2->data;
InsertNode(L, newnode);
}
return newnode->data;
}
void TraverseTree(HtNodePtr Ht, char code[], int k, HtTaLiPtr HtTableList)
{
if (Ht->lchild == NULL && Ht->rchild == NULL)
{
code[k] = '\0';
//printf("%s\n", code);
HtTablePtr newnode = (HtTablePtr)malloc(sizeof(HtTable));
newnode->next = NULL;
newnode->data = Ht->data;
newnode->s = (char*)malloc((strlen(code) + 1) * sizeof(char));
strcpy(newnode->s, code);
//printf("%s\n", newnode->s);
HtTableList->tail->next = newnode;
HtTableList->tail = newnode;
return;
}
if (Ht->lchild != NULL)
{
code[k] = '0';
TraverseTree(Ht->lchild, code, k + 1, HtTableList);
}
if (Ht->rchild != NULL)
{
code[k] = '1';
TraverseTree(Ht->rchild, code, k + 1, HtTableList);
}
}
void CreatTable(HtTreePtr tree, HtTaLiPtr HtTableList)
{
int k = 0;
char code[256] = {'\0'};
TraverseTree(tree->root, code, k, HtTableList);
}
void EnCode(HtTaLiPtr HtTableList)
{
fflush(stdin);
HtTablePtr node;
//puts("请输入字符串,最长30");
FILE* fp;
FILE* fp1;
if ((fp = fopen("C://Users/17681/Desktop/ToBeTran.txt", "r")) == NULL)
{
puts("ToBeTran.txt文件打开失败!");
}
if ((fp1 = fopen("C://Users/17681/Desktop/CodeFile.txt", "w")) == NULL)
{
puts("odeFile.txt文件打开失败!");
}
char ch = fgetc(fp);
while (!feof(fp))
{
node = HtTableList->head->next;
while (node != NULL)
{
if (ch == node->data)
{
fprintf(fp1,"%s\n", node->s);
break;
}
else
{
node = node->next;
}
}
ch = fgetc(fp);
}
fclose(fp);
fclose(fp1);
}
void PrintTree(HtNodePtr Ht,char* s, char* s1, FILE* fp)
{
if (Ht == NULL)
{
return;
}
printf("%s%c\n", s1, Ht->data);
fprintf(fp, "%s%c\n", s1, Ht->data);
for (int i = 0; i < 2; i++)
{
*s = ' ';
s++;
}
PrintTree(Ht->lchild, s, s1, fp);
PrintTree(Ht->rchild, s, s1, fp);
}
void DeCode(HtTreePtr tree)
{
FILE* fp;
if ((fp = fopen("C://Users/17681/Desktop/CodeFile.txt", "r")) == NULL)
{
puts("CodeFile.txt文件打开失败!");
}
FILE* fp1;
if ((fp1 = fopen("C://Users/17681/Desktop/TextFile.txt", "w")) == NULL)
{
puts("TextFile.txt文件打开失败!");
}
HtNodePtr node = tree->root;
fflush(stdin);
char ch[256];
fscanf(fp, "%s", ch);
while (!feof(fp))
{
for (int i = 0; i < strlen(ch); i++)
{
if (node->lchild == NULL && node->rchild == NULL)
{
fprintf(fp1, "%c", node->data);
//printf("%c", node->data);
node = tree->root;
}
if (ch[i] == '0')
{
node = node->lchild;
}
if (ch[i] == '1')
{
node = node->rchild;
}
}
fscanf(fp, "%s", ch);
}
fprintf(fp1, "%c", node->data);
fclose(fp);
fclose(fp1);
}
void WriteTree(HtTreePtr tree)
{
FILE* fp;
if ((fp = fopen("C://Users/17681/Desktop/hfmTree.txt","ab+")) == NULL)
{
puts("hfmTree.txt文件打开失败!");
return;
}
TreaseWrite(tree->root, fp);
fclose(fp);
puts("哈夫曼树写入文件");
}
void TreaseWrite(HtNodePtr Ht, FILE* fp)
{
if (Ht == NULL)
{
return;
}
if ((fwrite(Ht, sizeof(HtNode), 1, fp) != 1))
{
puts("哈夫曼树写入文件失败!");
}
TreaseWrite(Ht->lchild,fp);
TreaseWrite(Ht->rchild,fp);
}
void PrintCodeFile()
{
FILE* fp;
FILE* fp1;
if ((fp = fopen("C://Users/17681/Desktop/CodeFile.txt", "r")) == NULL)
{
puts("CodeFile.txt文件打开失败!");
}
if ((fp1 = fopen("C://Users/17681/Desktop/CodePrin.txt", "w")) == NULL)
{
puts("CodePrin文件打开失败!");
}
char* s = (char*)malloc(sizeof(char) * 30);
fscanf(fp, "%s", s);
while (!feof(fp))
{
printf("%s", s);
fprintf(fp1,"%s", s);
fscanf(fp, "%s", s);
}
fclose(fp);
fclose(fp1);
}