[Sonia] Implementation of Huffman Algorithm

 首次使用自顶向下的方法进行编程,初步感受到了增量式编码与调试的优点,能独立解决编程过程中出现的各种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;
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值