首次使用自頂向下的方法進行編程,初步感受到了增量式編碼與調試的優點,能獨立解決編程過程中出現的各種Bug。 進步明顯且迅速,特此表揚,(*^__^*) ……
//File name: h_tree.h
#ifndef _H_TREE_H_
#define _H_TREE_H_
#define MAX_NODES 100
#define MAX_CODE_LEN 100
#define MAX_SYMBOL_LEN 100
//#define DEBUG
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct h_tree{
int freq;
int code;
h_tree* next;
h_tree* left;
h_tree* right;
h_tree* father;
};
struct code_node{
int start;
int code[MAX_CODE_LEN];
};
struct symbol_node{
char symbol[MAX_SYMBOL_LEN];
int freq;
h_tree* node;
};
int read_data(char* file_name_in, struct symbol_node* nodes[], int* length);
struct h_tree* init_symbol_set(struct symbol_node* nodes[]);
struct h_tree* create_htree(struct h_tree* symbol_set);
int huf_code(struct symbol_node* nodes[], struct h_tree* root, char* file_name_out, int length);
void free_htree(struct h_tree* root);
struct h_tree* make_tree(int freq);
struct h_tree* insert(struct h_tree* node, struct h_tree* head);
int write_file(FILE* fp, struct symbol_node* nodes,struct code_node* code, int length);
struct code_node* make_code();
#ifdef DEBUG
void print_symbol_node(struct symbol_node* p);
void print_symbol_set(struct h_tree* head);
#endif
#endif
// File name: h_tree.cpp
#include "h_tree.h"
int read_data(char* file_name, struct symbol_node* nodes[], int* length)
{
int i = 0;
int freq = 0;
FILE* fp = NULL;
struct h_tree* p = NULL;
char symbol[MAX_SYMBOL_LEN] = {0};
(*length) = 0; //初始化節點的長度
if((fp = fopen(file_name, "r")) == NULL) //打開文件
{
printf("Can not open the file!\n");
exit(-1);
}
while(!feof(fp) && i < MAX_NODES) //讀取symbol和freq數據
{
fscanf(fp, "%s", symbol);
fscanf(fp, "%d", &freq);
nodes[i] = (struct symbol_node*) malloc(sizeof(struct symbol_node));
if(nodes[i] == NULL)
{
printf("Allocation fails!");
exit(-1);
}
strcpy(nodes[i]->symbol, symbol);
nodes[i]->freq = freq;
nodes[i]->node = NULL;
i++;
}
if(!feof(fp)) //若文件未達到文件尾,即MAX_SYMBOL_LEN設置過小,數組溢出
{
printf("Too many symbols in the file. Please adjust the value of MAX_SYMBOL_LEN !\n");
exit(-1);
}
(*length) = i; //記錄節點的個數
fclose(fp);
return 0;
}
struct h_tree* init_symbol_set(struct symbol_node* nodes[]) //初始化符號集合
{
int i = 0;
struct h_tree* head = NULL;
struct h_tree* node = NULL;
head = make_tree(0); //新建一個空的頭結點
while(nodes[i] != NULL)
{
node = make_tree(nodes[i]->freq);
nodes[i]->node = node; //將該h_tree節點指針存回nodes[i]中 以便後續從葉子節點查找哈夫曼編碼
head = insert(node, head); //按照freq從小到大的順序排成有序鏈表
i++;
}
return head;
}
struct h_tree* insert(struct h_tree* node, struct h_tree* head) //插入排序
{
struct h_tree* p = NULL;
struct h_tree* p_pre = NULL;
if(head->next == NULL)
{
head->next = node;
return head;
}
p = head->next;
p_pre = head;
while(p != NULL)
{
if(node->freq > p->freq)
{
p_pre = p;
p = p->next;
}
else break;
}
if(p == NULL) p_pre->next = node;
else
{
p_pre->next = node;
node->next = p;
}
return head;
}
struct h_tree* make_tree(int freq)
{
h_tree* node = NULL;
node = (struct h_tree *) malloc(sizeof(struct h_tree));
if(node == NULL)
{
printf("Allocation fails!");
exit(-1);
}
node->code = -1;
node->father = node->left = node->next = node->right = NULL;
node->freq = freq;
return node;
}
struct h_tree* create_htree(struct h_tree* symbol_set)
{
struct h_tree* p = NULL;
struct h_tree* q = NULL;
struct h_tree* node = NULL;
struct h_tree* root = NULL;
struct h_tree* head = symbol_set;
while(head->next->next != NULL)
{
p = head->next; //Get-min
head->next = p->next;
p->next =NULL; //Delete p
q = head->next; //Get-min
head->next = q->next;
q->next = NULL; //Delete q
root = node = make_tree(p->freq + q->freq); //new h_tree node
root->left = p; //
root->right = q;
p->father = root;
q->father = root;
p->code = 0;
q->code = 1;
head = insert(node, head);
#ifdef DEBUG
print_symbol_set(head);
#endif
}
return root;
}
int huf_code(struct symbol_node* nodes[], struct h_tree* root, char* file_name_out, int length)
{
int i = 0;
struct code_node* code[MAX_SYMBOL_LEN] = {NULL};
struct h_tree* p = NULL;
FILE* fp = NULL;
if(root == NULL)
{
printf("The h_tree is empty!\n");
exit(-1);
}
if((fp = fopen(file_name_out, "w")) == NULL)
{
printf("Can not open the file!\n");
exit(-1);
}
for(i = 0; i < length; i++)
{
code[i] = make_code(); //新建code節點
p = nodes[i]->node; //p指向葉子節點
while(p != root)
{
code[i]->start = code[i]->start - 1;
if(code[i]->start >= 0)
{
code[i]->code[code[i]->start]= p->code;
p = p->father;
}
else //編碼的數量過多 數組溢出
{
printf("Too many codes! Please adjust the value of MAX_CODE_LEN !\n");
exit(-1);
}
}
write_file(fp, nodes[i],code[i], length); //將原字符串和編碼寫入新文件
}
fclose(fp);
return 0;
}
int write_file(FILE* fp, struct symbol_node* node, struct code_node* code, int length)
{
int i = 0;
if(fp == NULL)
{
printf("File open error!\n");
exit(-1);
}
fprintf(fp, "%s ", node->symbol); //寫入字符串
for(i = code->start; i < MAX_CODE_LEN; i++) //寫入編碼
fprintf(fp, "%d ", (code->code)[i]);
fprintf(fp, "\n");
return 0;
}
struct code_node* make_code()
{
int i = 0;
struct code_node* node = NULL;
node = (struct code_node*) malloc(sizeof(struct code_node));
if(node == NULL)
{
printf("Allocation fails!");
exit(-1);
}
node->start = MAX_CODE_LEN;
for(i = 0; i < MAX_CODE_LEN; i++) (node->code)[i] = -1; //初始化code值爲-1
return node;
}
void free_htree(struct h_tree* root)
{
struct h_tree* p = NULL;
if(root != NULL)
{
p = root;
if(p->left != NULL) free_htree(p->left);
if(p->right != NULL) free_htree(p->right);
free(p);
}
}
#ifdef DEBUG
void print_symbol_node(struct symbol_node* p)
{
if( p != NULL)
{
printf("\nsym = %10s, freq = %d", p->symbol, p->freq);
}
}
void print_symbol_set(struct h_tree* head)
{
struct h_tree* p = head->next;
while(p != NULL)
{
printf("\n@freq = %d", p->freq);
p = p->next;
}
}
#endif
// File name: main.cpp
#include "h_tree.h"
int main()
{
int length = 0;
char file_name_in[100] = "data.txt";
char file_name_out[100] = "code.txt";
struct h_tree* root= NULL;
struct h_tree* symbol_set= NULL;
struct symbol_node* nodes[MAX_NODES] = {NULL};
read_data(file_name_in, nodes, &length); //讀取數據
#ifdef DEBUG
for(int i =0; i < length; i++)
{
print_symbol_node(nodes[i]);
}
#endif
symbol_set = init_symbol_set(nodes);
#ifdef DEBUG
print_symbol_set(symbol_set);
#endif
root = create_htree(symbol_set); //建立哈夫曼樹
huf_code(nodes, root, file_name_out, length); //哈夫曼編碼
free_htree(root); //釋放內存空間
return 0;
}