小任的第一篇博客-哈夫曼树

哈夫曼树

主要介绍哈夫曼树的构建,遍历(先序遍历、中序遍历、后序遍历)、哈弗曼编码实现、哈夫曼译码实现。

哈夫曼树功能实现

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;

#define OK 1
#define N 100
typedef struct {
	int num;//下标
	int weight;
	int parent, lchild, rchild;
}HTNode, * HuffmanTree;

typedef char  ** HuffmanCode;

//选择两个最小的数构建哈夫曼树
void Select(HuffmanTree& HT, int  m, int& s1, int& s2) {
	HuffmanTree p, q, pmin1 = NULL, pmin2 = NULL;
	p = HT + 1;//p指向下标为1的结点
	while (p->parent != 0)  p++;
	pmin1 = p; pmin2 = p + 1;
	while (pmin2->parent != 0) pmin2++;
	for (q = pmin2; q <= HT + m; q++) {                  //遍历所有结点找到权值最小的两个结点
		if (q->parent == 0 && q->weight < pmin1->weight) {
			pmin2 = pmin1; pmin1 = q;
		}//if
		else if (q->parent == 0 && q->weight < pmin2->weight) {
			pmin2 = q;
		}
	}//for
	s1 = pmin1->num;
	s2 = pmin2->num;
}

//Visit函数
int PrintHuffman(int weight){
	printf("%5d",weight);//输出权重
	return weight;
}

//输出哈夫曼树
void PrintHuffmanTree(HuffmanTree& HT, int m) {
	int i;
	HuffmanTree p = HT + 1;
	printf("i\tweight\tparent\tlchild\trchild\n");
	for (i = 1; i <= m; i++, p++)
		printf("%d\t%d\t%d\t%d\t%d\n", p->num, p->weight, p->parent, p->lchild, p->rchild);

}
//编码输出函数
void 	PrintHuffmanCode(HuffmanTree HT,HuffmanCode HC,int n){
	int i;
	printf("输出各权值对应的编码:\n");
	printf("权值\t编码\n");
	for(i=1;i<=n;i++)
		printf("%d\t%s\n",HT[i].weight,HC[i]);

}

//构建哈夫曼树
void HuffmanBuding(HuffmanTree& HT, HuffmanCode& HC, int* w, int n) {
	//w存放n个字符的权值(均>0),构造哈夫曼树HT,并求出n个字符的哈夫曼编码HC
	
	int s1, s2, f, c, i, m, start;
	if (n <= 1) return;
	m = 2 * n - 1;
	HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode));   //0号单元未用
	for (i = 1; i <= n; ++i, ++w) {
		HT[i].num = i; 
		HT[i].weight = *w;//将下标为i的结点权值放入w中
		HT[i].parent = 0; HT[i].lchild = 0; HT[i].rchild = 0;//初始为0
	}
	for (;i <= m; ++i) {                 //i=n+1
		HT[i].num = i; HT[i].weight = 0; HT[i].parent = 0; HT[i].lchild = 0; HT[i].rchild = 0;
	}
	printf("输出HT表的初态:\n");
	PrintHuffmanTree(HT, m);
	for (i = n + 1; i <= m; ++i) {
		//在HT[1..i-1]选择parent为0且weight最小的两个结点,其序号分别为s1和s2
		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;
	}
	printf("输出HT表的终态:\n");
	    PrintHuffmanTree(HT, m);
}
	
	//---从叶子到根逆向求每个字符的哈夫曼编码---
	void HuffmanTreeCoding(HuffmanTree HT,HuffmanCode& HC, int* w, int n){
	char* cd;
	HC = (HuffmanCode)malloc((n + 1) * sizeof(char*));  //分配n个字符编码的头指针向量
	cd = (char*)malloc(n * sizeof(char));    //分配求编码的工作空间
	cd[n - 1] = '\0';      //编码结束符
	for (int i = 1; i <= n; ++i) {     //逐个字符求哈夫曼编码
		int start = n - 1;         //编码结束符位置
		for (int c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent)  //从叶子到根逆向求编码,若不是根结点则进行编码
			if (HT[f].lchild == c) cd[--start] = '0';//如果为左孩子,编码为0
			else cd[--start] = '1';//右孩子编码为1
		HC[i] = (char*)malloc((n - start) * sizeof(char));  //为第i个字符编码分配空间
		strcpy(HC[i], &cd[start]);     //从cd复制编码(串)到HC
	}
	free(cd);
	PrintHuffmanCode(HT,HC,n);
	}

	//对哈夫曼树进行先序遍历
void PreOrder(HuffmanTree HT,int x,int(*Visit)(int weight)){
  if(x>0){
	  Visit(HT[x].weight);//输出下标为x的结点的值
	  if(HT->lchild) PreOrder(HT,HT[x].lchild,Visit);
	  if(HT->rchild) PreOrder(HT,HT[x].rchild,Visit);

  }}

//哈夫曼树中序遍历
void MidOrder(HuffmanTree HT,int x,int(*Visit)(int weight)){
	if(x>0){
		MidOrder(HT,HT[x].lchild, Visit);//输出左孩子
		Visit(HT[x].weight);
		MidOrder(HT,HT[x].rchild, Visit);//输出右孩子
	}}


//后序递归遍历哈夫曼树
void PostOrder(HuffmanTree HT, int x,int(*Visit)(int weight)) {
	if (x>0) {
		PostOrder(HT,HT[x].lchild, Visit);
		PostOrder(HT,HT[x].rchild, Visit);
		Visit(HT[x].weight);

	}}

//哈夫曼译码
void HuffmanTranslating(HuffmanTree HT,HuffmanCode& HC,int n)
{
   int i=0,j,k;
   char temp[N];
   char a[N];
   k = 0;
   i = 0;
   int*w=NULL;
   HuffmanTreeCoding(HT,HC,w,n);
   printf("请根据上表,输入所要译出的编码,不得输入空格\n");
	scanf("%s",a);
	//遍历输入的编码,从编码表查找。
   while(a[i]!='\0'){
   	temp[k] = a[i];//将字符数组a中的字符附给temp,a继续接受新的字符串
   	k++;
   	temp[k] = '\0';
   	//从编码表中找出相应的字符 
   	for(j=1;j<=n;j++){
   		if(!(strcmp(temp,HC[j]))){
   			k = 0;
			printf("%d",HT[j].weight);
   			break;
   		}
   	}
   	if(k>N)
   		printf("这串编码有问题,请重新检查!!\n"); //判断k值是否超过数组长度
   	i++;

   }}
void  main()
{
	HuffmanTree HT = NULL;
	HuffmanCode HC = NULL;
	int (*Visit)(int weight);
	Visit = PrintHuffman;
	int* w, * p;
	int enter=1;
	int x=0;
	int n, i,choice;
	while(enter){
	printf("\n");
	printf("******哈夫曼树功能菜单*******\n");
	printf("1、创建一个哈夫曼树\n");
	printf("2、对哈夫曼树进行遍历\n");
	printf("3、对哈夫曼树进行编码\n");
	printf("4、对哈夫曼树进行译码\n");
	printf("5、退出\n");
	printf("请输入你的选择:");
	scanf("%d",&choice);
	switch(choice){
	case 1:
	printf("请输入哈夫曼结点个数:");
	cin >> n;
	x=2*n-1;
	printf("请输入哈夫曼树各个结点的权值:");
	w = (int*)malloc(n * sizeof(int));
	for (i = 1, p = w; i <= n; ++i, ++p)
	cin >> *p;
	HuffmanBuding(HT, HC, w, n);
	break;
	case 2:
	printf("先序遍历结果为:");
	PreOrder(HT,x,Visit);
	printf("\n");
	printf("中序遍历结果为:");
	MidOrder(HT,x,Visit);
	printf("\n");
	printf("后序遍历结果为:");
	PostOrder(HT,x,Visit);
	break;
	case 3:
	HuffmanTreeCoding(HT, HC, w, n);
	break;
	case 4:
	HuffmanTranslating(HT,HC,n);
	break;
	case 5:
		enter=0;
		exit(0);
	default:
		printf("输出有误,请重新输入:");
		break;
	}
	system("pause");
	}
}

以上为哈夫曼树功能实现代码

输出

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
以上为哈夫曼树各项功能具体实现结果。
感谢阅读。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值