哈夫曼树的编码及译码(含代码)

**

哈夫曼树(编码及译码)

**
初学数据结构哈夫曼树(小菜鸟),借用了一些经典教材案例,编译软件为vs2013,有问题能指点,当然不喜勿喷哦,谢谢大家。
此程序是利用哈夫曼树实现对文本文件的加密与解密,程序所能达到的内容:使用从文件中读取显示原文本文件、使用哈夫曼树编码对文本文件进行加密、使用哈夫曼表显示字符编码、显示加密文件、使用哈夫曼树译码文本文件解密、显示解密文件、这些程序执行完以后,退出系统。主要包含以下内容:
1.输入文件所存在的位置;
2.进入主菜单界面,显示所有可操作的选项;
3.显示jiemi.txt文件的内容;
4.对文件进行加密,将其与字符转换为二进制编码;
5.对文件进行解密,将二进制编码写入;
6.从文件中读取二进制编码转换为字符,再写入文件;
7.退出系统。
原文件内容:

构建哈夫曼树

从文件中读入字符个数,判定权值最大值,因为了方便给构建哈夫曼树,每个节点的权值相差为1,也就是{1 2 3 4 5 ……n}第一步先取两个最小权值作为左右子树构造一个新树,取1,2构成新树,其结点为1+2=3 虚线为新生成的结点,第二步再把新生成的权值为3的结点放到剩下的集合中,再根据第二步,取最小的两个权值构成新树,再不断重复步骤建立哈夫曼树。

void Great(hufmantree &ht, int n)//n为从文件中读入字符的个数
{
	int m, S1, i, S2;
	m = 2 * n - 1;
	for (i = n + 1; i <= m; ++i)
	{

		select(ht, i - 1, S1, S2);/*选择权值最小的作为最小的节点*/	
		ht[S1].parent = i;
		ht[S2].parent = i;
		ht[i].lchild = S1;
		ht[i].rchild = S2;
	    ht[i].weight = ht[S1].weight + ht[S2].weight;
}

实现哈夫曼编码

void HuffmanCode(hufmantree ht, int n, huffmancode &hc)
{
	char *cd;
	int strat;
	hc = new char*[n + 1];
	cd = new char[n];
	cd[n - 1] = '\0';//最后一个给‘\0’
	int c, i, f;
	for (i = 1; i <= n; ++i)
	{
		strat = n - 1;//确定最后一个
		c = i;
		f = ht[i].parent;//f—>第i个的节点的双亲
		while (f != 0)
		{
			--strat;//cd倒数第二个空
			if (ht[f].lchild == c)//看看左边有没有孩子
				cd[strat] = '0';
			else cd[strat] = '1';//右边有没有孩子
			c = f; f = ht[f].parent;//回到双亲,f->i的双亲


		}
		hc[i] = new char[n - strat];
		strcpy_s(hc[i], strlen(cd) + 1, &cd[strat]);
	}

//	delete cd;
}

实现哈夫曼译码

void HuffmanCoding(hufmantree ht, int n, huffmancode hc, char b[100])
{
	cout << endl;
	int d, i = 1, j;
	char *cd;
	d = n * 2 - 1;
	cd = new char[n];
	char c;
	for (i = 1; i <= n; i++)
	{
		strcpy_s(cd, strlen(hc[i]) + 1, hc[i]);//从hc里把编码调过来
	for (j = 0; j <strlen(cd); j++)
		{
			c = cd[j];
			if (c == '0')
			{
				d = ht[d].lchild;/如果是0往走孩子走

			}
			if (c == '1')
			{

				d = ht[d].rchild;//如果是1往右孩子走
			}
		}
	cout << ht[d].weight << "   " << ht[d].zifu<<endl;
		d = n * 2 - 1;
	}
	delete cd;
	//往文件里写入编译好的字符
	char bf[100];
for (i = 0; i < n;i++)
	bf[i] = '\0';
	FILE *fp = fopen(b, "w+");
	for (i = 1; i <= n; i++)
	if (ht[i].zifu != '\0')
	{
		bf[i - 1] = ht[i].zifu;
		fprintf_s(fp,"%c", bf[i-1]);
		}
	
	fclose(fp);
}

**

完整代码

**

#include 
#include 
using namespace std;
typedef char elemtype;
typedef int status;
typedef char **huffmancode;
typedef struct
{
	char zifu;
	status weight;
	status parent, lchild, rchild;
}hufman, *hufmantree;
void Great(hufmantree &ht, int n);
status  chushihua(hufmantree &ht, char a[100],int n);
status select(hufmantree ht, int m, int &S1, int &S2);
void HuffmanCode(hufmantree ht, int n, huffmancode &hc);
void HuffmanCoding(hufmantree ht, int n, huffmancode hc, char b[100]);

void Zifubianma(huffmancode hc, int n, char a[]);
status wenben(char a[]);
void jiemi(hufmantree ht,  int n);
void Menu();
status duxu(char a[],char b[100]);
void xianshi(huffmancode hc, int n, char b[100]);
	int main()
{
		hufmantree ht;
		huffmancode hc;
		char a[100];
		char b[100];
		int  n;
	    n=duxu(a,b);
	    chushihua(ht, a,n);
		Great(ht, n);
		while (1)
		{
			Menu();
			printf("输入要做的操作:(1-7):  \n");
			int x;
			cin >> x;
			switch (x)
			{
			case 1:wenben(a); break;
			case 2: HuffmanCode(ht, n, hc); system("pause"); break;
			case 3:Zifubianma(hc, n,a); system("pause"); break;
			case 4:xianshi(hc,n,b);system("pause");break; 
			case 5: jiemi(ht,  n); system("pause"); break;
			case 6:HuffmanCoding(ht, n, hc,b); system("pause"); break;
			case 7:
			case 0:exit(0);

			}
			system("cls");
		}

		return 0;
	}
	

void Menu()
{
	printf_s("\n\t\t         ---------------------超级文件加密系统-------------------\n");
	printf_s("\n\t\t\t ψ卍ψ                   0.退出                    ψ卍ψ\n");
	printf_s("\n\t\t\t ψ卍ψ                   1.显示原文本文件          ψ卍ψ\n");
	printf_s(" \n\t\t\t ψ卍ψ                   2.文本文件加密            ψ卍ψ    \n");
	printf_s(" \n\t\t\t ψ卍ψ                   3.显示字符编码            ψ卍ψ\n");
	printf_s(" \n\t\t\t ψ卍ψ                   4.显示加密文件            ψ卍ψ \n");
	printf_s("\n\t\t\t ψ卍ψ                   5.文本文件解密            ψ卍ψ \n ");
	printf_s(" \n\t\t\t ψ卍ψ                   6.显示解密文件            ψ卍ψ \n");
	printf_s(" \n\t\t\t ψ卍ψ                   7.退出系统                ψ卍ψ \n");
	printf_s("\n\t\t         --------------------------------------------------------\n");
}
status wenben(char a[])
{
	int i;
	for (i = 0; i <= strlen(a) - 1; i++)
cout << a[i];
	system("pause");
	return 0;

}
status duxu(char a[],char b[100])
{
	
	cout << "输入文件所在位置"<<endl;
	gets(b);
	FILE *fp = fopen(b, "r");
	int i=100;
fgets(a,i, fp);

	fclose(fp);
	i = 0; 
	while (a[i] !='\0')
	{
		i++;
	}
	
	return i;
}
status  chushihua(hufmantree &ht,char a[100],int n)
{
	int  i, m;
	//cin >> n;/*输入结点1--n之间的节点*/
	m = 2 * n - 1;/*m用于开辟两倍的ht的空间*/
	ht = new hufman[m + 1];/*同上*/
	for (i = 1; i <= m; i++)
	{
		ht[i].parent = 0; ht[i].lchild = 0; ht[i].rchild = 0;
		ht[i].zifu = '0';
	}

	for (i = 1; i <= n; i++)
	{
			
		 ht[i].weight=i;/*输入前几个节点的权值课本p138*/	
		ht[i].zifu = a[i-1];
	}

	return n;
}
void Great(hufmantree &ht, int n)
{
	int m, S1, i, S2;
	m = 2 * n - 1;
	for (i = n + 1; i <= m; ++i)
	{
		
		select(ht, i - 1, S1, S2);/*选择权值最小的作为最小的节点*/		
		ht[S1].parent = i;
		ht[S2].parent = i;
		ht[i].lchild = S1;
		ht[i].rchild = S2;
	    ht[i].weight = ht[S1].weight + ht[S2].weight;

	}
	

}status select(hufmantree ht, int m, int &S1, int &S2)
{
	int j;
	for (j = 1; j <= m; j++)
	{
		if (ht[j].parent == 0)
		{
			S1 = j;
			break;
		}
	}
	for (j = 1; j <= m; j++)
	{
		if (ht[j].parent == 0 && j != S1)
		{
			S2 = j;
			break;
		}
	}
	for (j = 1; j <= m; j++)
	{



		if (ht[j].parent == 0 && ht[j].weight < ht[S1].weight)
		{
			S1 = j;
	
		}

	}
	for (j = 1; j <= m; j++)
	{

		if (ht[j].parent == 0 && j != S1&&ht[j].weight < ht[S2].weight)//双亲为0j不等于上
		{
			S2 = j;
			}


	}
	return 0;
}


void HuffmanCode(hufmantree ht, int n, huffmancode &hc)
{
	char *cd;
	int strat;
	hc = new char*[n + 1];
	cd = new char[n];
	cd[n - 1] = '\0';//最后一个给o
	int c, i, f;
	for (i = 1; i <= n; ++i)
	{
		strat = n - 1;//确定最后一个
		c = i;
		f = ht[i].parent;//f—>第i个的节点的双亲
		while (f != 0)
		{
			--strat;//cd倒数第二个空
			if (ht[f].lchild == c)//看看左边有没有孩子
				cd[strat] = '0';
			else cd[strat] = '1';//右边有没有孩子
			c = f; f = ht[f].parent;//回到双亲,f->i的双亲


		}
		hc[i] = new char[n - strat];
		strcpy_s(hc[i], strlen(cd) + 1, &cd[strat]);
	}
	cout << "文本文件加密成功!";
//	delete cd;
}
void jiemi(hufmantree ht ,int n){
	printf_s("   显示字符编码(哈夫曼表)\n");cout << "位置 右子树 左子树 双亲 对应字符"<<endl;
	int i; for (i = 1; i <= 2 * n - 1; i++)
	{
		
		printf_s("%2d", i);
		printf_s("%6d%6d%6d%6c\n", ht[i].rchild, ht[i].lchild, ht[i].parent, ht[i].zifu);
	}
	
	cout << "解密成功!";
}
void HuffmanCoding(hufmantree ht, int n, huffmancode hc, char b[100])
{
	cout << endl;
	int d, i = 1, j;
	char *cd;
	d = n * 2 - 1;
	cd = new char[n];
	char c;
	for (i = 1; i <= n; i++)
	{
		strcpy_s(cd, strlen(hc[i]) + 1, hc[i]);

	for (j = 0; j <strlen(cd); j++)
		{
			c = cd[j];
			if (c == '0')
			{
				d = ht[d].lchild;

			}
			if (c == '1')
			{

				d = ht[d].rchild;
			}
		}
	cout << ht[d].weight << "   " << ht[d].zifu<<endl;
		d = n * 2 - 1;
	}
	delete cd;
	char bf[100];

	for (i = 0; i < n;i++)
	bf[i] = '\0';
	FILE *fp = fopen(b, "w+");
	for (i = 1; i <= n; i++)
	if (ht[i].zifu != '\0')
	{
		bf[i - 1] = ht[i].zifu;
		fprintf_s(fp,"%c", bf[i-1]);
		}
	
	fclose(fp);
}
void Zifubianma(huffmancode hc, int n, char a[])
{
	printf_s("   显示字符编码\n");
	int i; for (i = 1; i <= n; i++)
	{
		cout << a[i - 1] << "  " << hc[i] << endl;
	}
}
void xianshi(huffmancode hc, int n,char b[100])
{
	int i;

	printf_s("\n         4. 显示加密文件\n");
FILE *fp = fopen(b, "w+");
	for (i = 1; i <= n; i++)
	{
		cout <<hc[i];	fputs(hc[i], fp);	
	}
fclose(fp);
}

你可能感兴趣的:(哈夫曼树编码,哈夫曼树译码,构建哈夫曼树)