哈夫曼树的实现

输入字符集以及权值,建立哈夫曼树进行一系列操作;其中建立哈夫曼树,以及编码部分参考了百度百科;

#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;

const int MAXVALUE = 99999; //初始设定的权值最大值
const int MAXBIT = 10; //初始设定的最大编码位数
const int MAXN = 1000; //初始设定的最大结点个数

struct HaffNode //哈夫曼树的结点结构
{
	int weight; //权值
	int flag; //标记
	int parent; //双亲结点下标
	int leftChild; //左孩子下标
	int rightChild; //右孩子下标
};

struct Code //存放哈夫曼编码的数据元素结构
{
	int bit[MAXBIT]; //数组
	int start; //编码的起始下标
	int weight; //字符的权值
};

void Menu();
void Haffman(int weight[], int n, HaffNode haffTree[]);//建树
void HaffmanCode(HaffNode haffTree[], int n, Code haffCode[]);//生成哈夫曼编码
void Coding(char str[], char s[], int n, Code code[]);
void DeCoding(int n, char s[], HaffNode hafftree[]);
void ReadFile(char s[]);
void PreOrder(HaffNode haffTree[], int n);
void InOrder(HaffNode haffTree[], int n);

int main()
{
	int i, weight[MAXN], len;
	char strChar[MAXN], c;
	bool flag = true;
	HaffNode *hafftree;
	Code *haffcode;

	Menu();
	while(flag)
	{	
		cout << "please input:";
		cin >> c;
		switch(c)
		{
			case 'B':
			{
				cout << "please input string:";
				cin>>strChar;
				len = strlen(strChar);
				cout << "please input weight:";
				for(i=0; i<len; i++)
					cin >> weight[i];	
				hafftree = new HaffNode[2*len-1];
				Haffman(weight, len, hafftree);
			}
			break;

			case 'E':
			{
				haffcode = new Code[len];
				HaffmanCode(hafftree, len, haffcode);
			}
			break;

			case 'T':
			{
				PreOrder(hafftree, 2*len-2);
				cout << endl;
				InOrder(hafftree, 2*len-2);
				cout << endl;
			}
			break;

			case 'C':
			{
				char strInput[MAXN];
				cout << "please input string:";
				cin >> strInput;
				Coding(strInput, strChar, len, haffcode);
			}
			break;

			case 'D':
			{
				DeCoding(len, strChar, hafftree);
			}
			break;

			case 'P':
			{
				ReadFile("textfile.txt");
				ReadFile("codefile.txt");
				ReadFile("result.txt");
			}
			break;

			case 'X':
			{
				flag = false;
			}
			break;

			case 'S':
			{
				Menu();
			}
			break;

			default:
				break;
		}
	}
	return 0;
}

void Menu()
{
	cout<<"********************************************************************"<<endl;
	cout<<"* B—建树:   读入字符集和各字符频度,建立哈夫曼树。*****************"<<endl;
	cout<<"********************************************************************"<<endl;
	cout<<"* T—遍历:   先序和中序遍历二叉树。                *****************"<<endl;
	cout<<"********************************************************************"<<endl;
	cout<<"* E—生成编码: 根据已建成的哈夫曼树,产生各字符的哈夫曼编码。*******"<<endl;
	cout<<"********************************************************************"<<endl;
	cout<<"* C—编码:   输入由字符集中字符串组成的任意字符串,利用已生成的 ****"<<endl;
	cout<<"*            哈夫曼编码,显示编码结果,并将输入的字符串及其编码  ****"<<endl;
	cout<<"*            结果分别保存在磁盘文件textfile.txt和codefile.txt中。***"<<endl;
	cout<<"********************************************************************"<<endl;
	cout<<"* D—译码:   读入codefile.txt,利用建议建成的哈夫曼树进行译码,******"<<endl;
	cout<<"*            并将译码结果放入磁盘文件result.txt。             ******"<<endl;
	cout<<"********************************************************************"<<endl;
	cout<<"* P—打印:   屏幕显示文件textfile.txt、codefile.txt和result.txt。***"<<endl;
	cout<<"********************************************************************"<<endl;
	cout<<"* X—退出。                           ******************************"<<endl;
	cout<<"********************************************************************"<<endl;
}

void Haffman(int weight[], int n, HaffNode haffTree[])
//建立叶结点个数为n权值为weight的哈夫曼树haffTree
{
	int j, m1, m2, x1, x2;
	//哈夫曼树haffTree初始化。n个叶结点的哈夫曼树共有2n-1个结点
	for(int i = 0; i < 2 * n - 1 ; i++)
	{
		if(i < n)
			haffTree[i].weight = weight[i];
		else 
			haffTree[i].weight = 0;
		haffTree[i].parent = 0;
		haffTree[i].flag = 0;
		haffTree[i].leftChild = -1;
		haffTree[i].rightChild = -1;
	}
	//构造哈夫曼树haffTree的n-1个非叶结点
	for(i = 0;i < n-1;i++)
	{
		m1 = m2 = MAXVALUE;
		x1 = x2 = 0;
		for(j = 0; j < n+i;j++)
		{
			if (haffTree[j].weight < m1 && haffTree[j].flag == 0)
			{
				m2 = m1;
				x2 = x1;
				m1 = haffTree[j].weight;
				x1 = j;
			}
			else if(haffTree[j].weight < m2 && haffTree[j].flag == 0)
			{
				m2 = haffTree[j].weight;
				x2 = j;
			}
		}
	//将找出的两棵权值最小的子树合并为一棵子树
		haffTree[x1].parent = n + i;
		haffTree[x2].parent = n + i;
		haffTree[x1].flag = 1;
		haffTree[x2].flag = 1;
		haffTree[n+i].weight = haffTree[x1].weight + haffTree[x2].weight;
		haffTree[n+i].leftChild = x1;
		haffTree[n+i].rightChild = x2;
	}
}

void HaffmanCode(HaffNode haffTree[], int n, Code haffCode[])
//由n个结点的哈夫曼树haffTree构造哈夫曼编码haffCode
{
	Code *cd = new Code;
	int child, parent;
	//求n个叶结点的哈夫曼编码
	for(int i = 0; i < n; i++)
	{
		cd->start = n-1; //不等长编码的最后一位为n-1
		cd->weight = haffTree[i].weight; //取得编码对应权值的字符
		child = i;
		parent = haffTree[child].parent;
	//由叶结点向上直到根结点
		while(parent != 0)
		{
			if(haffTree[parent].leftChild == child)
			cd->bit[cd->start] = 0; //左孩子结点编码0
			else
			cd->bit[cd->start] = 1;//右孩子结点编码1
			cd->start--;
			child = parent;
			parent = haffTree[child].parent;
		}
	//保存叶结点的编码和不等长编码的起始位
		for(int j = cd->start+1; j < n; j++)
			haffCode[i].bit[j] = cd->bit[j];
		haffCode[i].start = cd->start;
		haffCode[i].weight = cd->weight; //保存编码对应的权值
	}
}

void Coding(char str[], char s[], int n, Code code[])
{
	ofstream outf("textfile.txt");
	int len = strlen(str);

	if(!outf)
	{
		cout << "cannot open the file\n";
		return ;
	}

	outf << str;
	outf << endl;
	outf.close();

	ofstream outfc("codefile.txt");
	if(!outfc)
	{
		cout << "cannot open the file\n";
		return ;
	}
	for(int i=0; i<len; i++)
	{
		for(int j=0; j<n; j++)
		{	
			if(str[i] == s[j])
				break;
		}
		for(int k=code[j].start+1; k<n; k++)
			outfc << code[j].bit[k];
	}
	outfc << endl;
	outfc.close();
}

void DeCoding(int n, char s[], HaffNode hafftree[])
{
	ifstream inf("codefile.txt");
	char str[MAXN];
	inf >> str;

	ofstream outf("result.txt");
	int len = strlen(str);

	int j = 2 * n - 2;
	for(int i=0; i<len; i++)
	{
		if('0' == str[i])
		{
			if(0 <= hafftree[j].leftChild && hafftree[j].leftChild < n)
			{
				outf << s[hafftree[j].leftChild];
				j = 2 * n - 2;
			}
			else
				j = hafftree[j].leftChild;
		}
		else
		{
			if(0 <= hafftree[j].rightChild && hafftree[j].rightChild < n)
			{
				outf << s[hafftree[j].rightChild];
				j = 2 * n - 2;
			}
			else
				j = hafftree[j].rightChild;
		}
	}

	inf.close();
	outf.close();
}

void ReadFile(char s[])
{
	ifstream inf(s);
	char str[MAXN];
	inf >> str;
	cout << s << ":" << str << endl;
	inf.close();
}

void PreOrder(HaffNode haffTree[], int n)
{
	if(n > -1)
	{
		cout << haffTree[n].weight << " ";
		PreOrder(haffTree, haffTree[n].leftChild);
		PreOrder(haffTree, haffTree[n].rightChild);
	}
}

void InOrder(HaffNode haffTree[], int n)
{
	if(n > -1)
	{
		InOrder(haffTree, haffTree[n].leftChild);
		cout << haffTree[n].weight << " ";
		InOrder(haffTree, haffTree[n].rightChild);
	}
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值