任务描述
本关任务:编写能对给定n
个叶子结点,构建哈夫曼树,给出每个叶子结点对应编码的程序。
相关知识
哈夫曼编码和译码的基本原理
-
首先要构造一棵哈夫曼树。哈夫曼树的结点结构包括权值,双亲,左右孩子;假如由
n
个字符来构造一棵哈夫曼树,则共有结点2n-1
个;在构造前,先初始化,初始化操作是把双亲,左右孩子的下标值都赋为0
;然后依次输入每个结点的权值。 -
第二步是通过
n-1
次循环,每次先找输入的权值中最小的两个结点,把这两个结点的权值相加赋给一个新结点,并且这个新结点的左孩子是权值最小的结点,右孩子是权值第二小的结点;鉴于上述找到的结点都是双亲为0
的结点,为了下次能正确寻找到剩下结点中权值最小的两个结点,每次循环要把找的权值最小的两个结点的双亲赋值不为0
(i
)。就这样通过n-1
循环下、操作,创建了一棵哈夫曼树,其中,前n
个结点是叶子(输入的字符结点)后n-1
个是度为2
的结点。 -
编码的思想是逆序编码,从叶子结点出发,向上回溯,如果该结点是回溯到上一个结点的左孩子,则在记录编码的数组里存
“0”
,否则存“1”
,注意是倒着存;直到遇到根结点(结点双亲为0
),每一次循环编码到根结点,把编码存在编码表中,然后开始编码下一个字符(叶子)
测试说明
平台会对你编写的代码进行测试:
测试输入:5 2 7 4 5 19
预期输出:(对哈夫曼树按中序遍历输出对应叶子的哈夫曼编码)
7 00
5 010
2 0110
4 0111
19 1
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
# include<malloc.h>
#include <iostream>
using namespace std;
#define max 1000;
struct HtNode {
int ww;//结点的权值
int parent, lch, rch;
char codes[10];//存放哈夫曼编码
};
struct HtTree {
int m;//叶子结点的个数
int root;//哈夫曼树根在数组的下标
struct HtNode ht[1000];//存放2m-1个节点的数组
};
typedef struct HtTree* HtTreee;
HtTreee creathuffman(int m, int* w)//创建哈弗曼树
{
int num = 2 * m - 1;
HtTreee huf;
int i, j, x1, x2, m1, m2;
huf = (HtTreee)malloc(sizeof(struct HtTree));;
//huf->ht = (struct HtNode*)malloc(sizeof(struct HtNode) * num);//分配空间
for (i = 0; i < num; i++) {
huf->ht[i].lch = huf->ht[i].parent = huf->ht[i].rch = -1;
if (i < m) {
huf->ht[i].ww = w[i];
}
else {
huf->ht[i].ww = -1;
}
}//初始化哈弗曼树
for (i = 0; i < m-1; i++) {
m1 = m2 = max;
x1 = x2 = -1;
for (j = 0; j < m + i; j++) {//寻找两个最小权的无父节点的结点
if (huf->ht[j].ww < m1 && huf->ht[j].parent == -1) {//x1存放最小的下标
m2 = m1; x2 = x1;
m1 = huf->ht[j].ww;x1 = j;
}
else if(huf->ht[j].ww < m2 && huf->ht[j].parent == -1) {//x1存放次小的下标
m2 = huf->ht[j].ww; x2 = j;
}
}
huf->ht[x1].parent = huf->ht[x2].parent = m + i;
huf->ht[m + i].ww = m1 + m2;
huf->ht[m + i].lch = x1; huf->ht[m + i].rch = x2;//默认右大左小
}
huf->root = 2 * m - 2;
return huf;
}
void huffmancodes(HtTreee huf,int n) {
char* temp;
temp = new char[n];
temp[n - 1] = '\0';
int start, pos, parent;
for (int i = 0; i < n; i++) {
start = n - 1;
pos = i;
parent = huf->ht[i].parent;
while (parent != -1) {
if (huf->ht[parent].lch == pos) {
temp[--start] = '0';
}
else
{
temp[--start] = '1';
}
pos = parent;
parent = huf->ht[parent].parent;
}
strcpy(&huf->ht[i].codes[0], &temp[start]);
}
delete temp;
}
void inOrderhuffman(HtTreee huf)
{
int i = huf->root;
if (huf->ht[i].lch==-1) {
cout << huf->ht[i].ww<<" " << huf->ht[i].codes << endl;
return;
}
huf->root = huf->ht[i].lch;
inOrderhuffman(huf);
huf->root = huf->ht[i].rch;
inOrderhuffman(huf);
}
int main() {
int m,ww;
cin >> m;//输入叶子结点个数
HtTreee huf;
int w[100];//存放权值
for (int i = 0; i < m; i++) {
cin >> ww;
w[i] = ww;
}
huf = creathuffman(m,w);
huffmancodes(huf, m);
inOrderhuffman(huf);
}