二叉树实现哈夫曼码

最近完成一个数据结构的作业,哈夫曼编码,实现了


1.查看字母的哈夫曼码
2.哈夫曼码转文字
3.文字转哈夫曼码


这几个功能


哈夫曼码主要用于压缩编码,将字符用二进制(0,1)编码代替,能过使出现概率大的字母的二进制码短,而我们会根据字符的出现概率给各个字符赋一个“权重”,再根据权重构造一个二叉树


核心便是如何构造这个哈夫曼二叉树


那么二叉树的结点结构要有4个元素weight(权重),left(左孩子),right(右孩子),parent(双亲结点)


首先假设我们有一个集合{2,4,5,3}即4个权重
1.选取两个最小的权重(2,3)构成二叉树最底部的叶子,它们的和是他们的parent
集合也就成了 {4,5,5}
2.重复第一步在4 ,5 ,5中选取两个较小的(优先选取还未在树上的4,5),集合变为{9,5}

3,重复以上二叉树也就成了


 Talk is cheap,show you the code   //我的环境是VS2013


// 哈夫曼.cpp : 定义控制台应用程序的入口点。
//
#include "fstream"
#include "iostream"
#include "string"
#define MAX 53
using namespace std;

double w[1000];
string low = "0";
string high = "1";
string Code[1000];

class Huffman_tree
{
public:
	void choose(Huffman_tree *h, int n, int &num_1, int &num_2);
	Huffman_tree* build_tree(Huffman_tree* &h, double *number, int n);
	friend void be_code();
	friend void coding(Huffman_tree *T, string code, int n);
	friend void de_code(Huffman_tree *T, string code, int &n);
	friend void show(Huffman_tree *T);
	Huffman_tree()
	{
		parent = NULL;
		left = NULL;
		right = NULL;
	}
private:
	Huffman_tree	*left;
	Huffman_tree	*right;
	double	weight;
	int parent;
};

void Huffman_tree::choose(Huffman_tree *h, int n, int &num_1, int &num_2)   //给哈夫曼树各个叶子结点选择权重
{
	double m1, m2;
	int i = 0;
	int j = 0;
	for (i = 0; i < n; i++)
	{
		if (h[i].parent == NULL)
		{
			m1 = h[i].weight;
			num_1 = i;
			j = i++;
			break;
		}
	}
	for (i = j; i < n; i++)
	{
		if (h[i].parent == NULL)
		{
			m2 = h[i].weight;
			num_2 = i;
		}
	}
	for (int i = j; i < n; i++)
	{
		if (h[i].parent == NULL&&i != num_1&&i != num_2)
		{
			if (h[i].weight < m1)
			{
				m2 = m1;
				num_2 = num_1;
				m1 = h[i].weight;
				num_1 = i;
			}
			else if (h[i].weight < m2)
			{
				m2 = h[i].weight;
				num_2 = i;
			}
		}
	}
}

Huffman_tree* Huffman_tree::build_tree(Huffman_tree* &h, double *number, int n)   //构造哈夫曼树
{
	int i, m,num1, num2;
	Huffman_tree *p;
	if (n < 2)	return	NULL;
	m = 2 * n - 1;
	h = new Huffman_tree[m];
	p = h;
	for (i = 0; i < n; ++i, ++p)
		p->weight = number[i];
	for (i = n; i < m; i++)
	{
		choose(h, i, num1, num2);
		h[i].left = &h[num1];
		h[i].right = &h[num2];
		h[num1].parent = i;
		h[num2].parent = i;
		h[i].weight = h[num1].weight + h[num2].weight;
	}
	return &h[m - 1];
}

void coding(Huffman_tree *T, string code, int n)  //给各个字母编码
{
	if (T != NULL)
	{
		string temp = code;
		code = code + low;
		if (T->left == NULL&&T->right == NULL)
			for (int i = 0; i < n; i++)
			{
				if (T->weight == w[i])
				{
					Code[i] = temp;
				}					
			}
		coding(T->left, code, n);
		code = temp;
		code = code + high;
		coding(T->right, code, n);
	}
}

bool read_file()  //从文件中读取各个字母的概率
{
	double weight = 0;
	ifstream infile;
	infile.open("probability.txt", ios::in);
	if (!infile)	cout << "Wrong" << endl;
	for (int i = 0; i < MAX; i++)
	{
		infile >> w[i];
		weight = weight + w[i];
	}
	if ((int)weight != 1)
	{
		cout << "您的概率相加不等于1" << endl;
		return 0;
	}
	else
	return 1;	
}

void de_code(Huffman_tree *T,string code,int &n)  //哈夫曼码转文字的递归算法,直接递归遍历哈夫曼树
{
	if (T != NULL)
	{
		if ((T->left == NULL&&T->right == NULL) || code[n] == '#')
		{
			for (int j = 0; j < MAX; j++)
			{
				if (T->weight == w[j])
				{
					if (j == 0)				cout << (char)32;
					else if (j < 27)		cout << (char)(j + 64);
					else					cout << (char)(j + 70);
				}
			}
		}
		else
		{
			if (code[n] == '0')
			{
				n = n + 1;
				de_code(T->left, code, n);
			}
			else
			{
				n = n + 1;
				de_code(T->right, code, n);
			}
		}		
	}
}

void show_word(Huffman_tree *root)  // 哈夫曼转文字递归算法的调用程序
{
	string code;
	int temp;
	int m = 0;
	system("cls");
	cout << "               1. 键入                 " << endl;
	cout << "               2. 读取文件             " << endl;
	cin >> temp;
	if (temp == 1)
	{
		cout << "请输入哈夫曼码,以#结尾" << endl;
		cin >> code;
		while (code[m] != '#')
		{
			de_code(root, code, m);
		}
	}
	if (temp == 2)
	{
		ifstream infile;
		infile.open("H.txt", ios::in);
		infile >> code;
		cout<<"从H.txt文件中读取"<<endl; 
		while (code[m] != '#')
		{
			de_code(root, code, m);
		}
		infile.close();
	}
}

void show_code(Huffman_tree *root)  // 展示字符的哈夫曼码
{
	char word;
	int i, j;
	string s, t;
	ofstream Outfile;
	Outfile.open("code.txt", ios::out);
	coding(root, s, MAX);
	cout << "各个字符的哈夫曼编码为" << endl;
	i = 32;
	for (j = 0; j < MAX; j++)
	{
		word = i;
		cout << word << "\t" << Code[j] << endl;
		Outfile << word << "\t" << Code[j] << endl;
		if (i == 32)
			i = 64;
		if (i == 90)
			i = 96;
		i++;
	}
	Outfile.close();
}

void be_code()  // 文字转哈夫曼码
{
	string word;
	ofstream Outfile;
	ifstream infile;
	Outfile.open("result.txt", ios::out);
	int n = 0;
	system("cls");
	cout << "请输入一段话,以#结束,空格用_(下划线)代替)" << endl;
	cin >> word;
	while (word[n] != '#')
	{
		int i = word[n];
		if (word[n] == '_')	i = 32;
		if (i == 32)
		{
			cout << Code[0];
			Outfile << Code[0];
		}
		else if (i < 91)
		{
			cout << Code[i - 64];
			Outfile << Code[i - 64];
		}
		else
		{
			cout << Code[i - 70];
			Outfile << Code[i - 70];
		}
		n++;
	}
}

void caidan()  //由于是课程设计的作业,得有个给老师看的界面
{
	cout << "*************************************************************************" << endl;
	cout << "*                       1.查看哈夫曼码                                  *" << endl;
	cout << "*                       2.哈夫曼码转文字                                *" << endl;
	cout << "*                       3.文字转哈夫曼码                                *" << endl;
	cout << "*                       4.退出                                          *" << endl;
	cout << "*************************************************************************" << endl;
}

int main()
{
	int temp = 0;
	if (read_file())
	{	
		Huffman_tree *buff = new Huffman_tree;
		Huffman_tree *root;
		root = buff->build_tree(buff, w, MAX);
		show_code(root);
		system("cls");
		while (temp != 4)
		{
			system("cls");
			caidan();
			cin >> temp;
			switch (temp)
			{
				case 1:show_code(root); break;
				case 2:show_word(root);	break;
				case 3:be_code();		break;
				default:				break;
			}
			system("pause");
		}		
	}	
	return 0;
}

当然这个代码写得很渣,有一种C语言风格的C++,之后肯定会慢慢地改正过来

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值