哈夫曼树
主要介绍哈夫曼树的构建,遍历(先序遍历、中序遍历、后序遍历)、哈弗曼编码实现、哈夫曼译码实现。
哈夫曼树功能实现
#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");
}
}
以上为哈夫曼树功能实现代码
输出
以上为哈夫曼树各项功能具体实现结果。
感谢阅读。