函數SelectTwoMin(int upbound, HuffmanTree HT, int &s1, int &s2)是從1到upbound中找出father為0的節點賦給s1,s2,(為了保證答案唯一,請讓s1的節點編號小於s2),函數HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n)是構造哈夫曼樹以及計算哈夫曼編碼。保證輸入的權重值小於1000。
函數接口定義:
void SelectTwoMin(int upbound, HuffmanTree HT, int &s1, int &s2);
void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n);
其中 upbound
編號,HT
是哈夫曼樹,HC
是哈夫曼編碼,w
是權值,n
是葉子節點個數。
裁判測試程序樣例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int weight;
int parent;
int lchild;
int rchild;
} HTNode, *HuffmanTree;
typedef char ** HuffmanCode;
void SelectTwoMin(int upbound, HuffmanTree HT, int &s1, int &s2);
void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n);
int main() {
HuffmanTree ht;
HuffmanCode hc;
int n;
scanf("%d", &n);
int *w = (int *) malloc (n * sizeof(int));
for(int i = 0; i < n; ++ i)
scanf("%d", &w[i]);
HuffmanCoding(ht, hc, w, n);
for (int i = 1; i <= 2 * n - 1; ++ i) {
printf("%d %d %d %d\n",
ht[i].weight, ht[i].parent, ht[i].lchild, ht[i].rchild);
}
for (int i = 1; i <= n; ++ i)
printf("%s\n", hc[i]);
free(w);
free(ht);
for (int i = 1; i <= n; ++ i)
free(hc[i]);
return 0;
}
/* 你的代碼將被嵌在這里 */
####輸入格式: 第一行輸入一個數n,表示葉子節點的個數,接下去輸入n個整數,表示每個節點的值
####輸出格式: 只要建樹即可,輸出已經確定了
輸入樣例:
4
1 2 3 4
輸出樣例:
1 5 0 0
2 5 0 0
3 6 0 0
4 7 0 0
3 6 1 2
6 7 3 5
10 0 4 6
110
111
10
0
這里直接上代碼,思路全在代碼的注釋里。
// 逆置編碼
void reverse(char *CH)
{
int n = strlen(CH);
for(int i = 0; i < n / 2; i++){
char temp;
temp = CH[i];
CH[i] = CH[n-i-1];
CH[n-i-1] = temp;
}
}
// 選出當前權值最小的兩個結點
void SelectTwoMin(int upbound, HuffmanTree HT, int &s1, int &s2)
{
int x1 = 0;
int x2 = 0;
int w1 = 1000;
int w2 = 1000;
for(int i = 1; i <= upbound; i++){
if(HT[i].parent == 0 && HT[i].weight < w1){
x2 = x1;
w2 = w1;
x1 = i;
w1 = HT[i].weight;
}
else if(HT[i].parent == 0 && HT[i].weight < w2){
x2 = i;
w2 = HT[i].weight;
}
}
s1 = x1;
s2 = x2;
}
void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n)
{
// 當前權值最小的兩個結點s1,s2
int s1 = 0;
int s2 = 0;
// 給哈夫曼樹和哈夫曼編碼分配空間
HT = (HuffmanTree)malloc(sizeof(HTNode)*(2*n)); // 一共2*n-1個結點,這個分配2*n個結點的空間
HC = (char **)malloc(sizeof(char *)*(n+1)); // 一共n個葉節點,這里分配n+1個結點空間
// 初始化哈夫曼編碼
for(int i = 1; i <= n; i++){
HC[i] = (char *)malloc(sizeof(char)*(n+1));
memset(HC[i], 0, sizeof(char)*(n+1));
}
// 初始化哈夫曼樹
for(int i = 0; i < n; i++){ // 因只給葉節點編碼,所以這個為n(n個葉結點)
HT[i+1].weight = w[i];
}
for(int i = 1; i <= 2*n-1; i++){ // 一共有2*n-1個結點
HT[i].parent = 0;
HT[i].lchild = 0;
HT[i].rchild = 0;
}
// 構建哈夫曼樹
for(int i = 0; i < n - 1; i++){
SelectTwoMin(n+i, HT, s1, s2); // 在當前哈夫曼樹中的n+i個有效結點中找出權值最小的兩個結點(初始化時有n個葉結點,n~(2*n-1)為分支結點)
// 給第n+i+1個節點賦值
HT[n+i+1].lchild = s1;
HT[n+i+1].rchild = s2;
HT[n+i+1].weight = HT[s1].weight + HT[s2].weight;
HT[s1].parent = n+i+1;
HT[s2].parent = n+i+1;
}
// 根據哈夫曼樹進行哈夫曼編碼
for(int i = 1; i <= n; i++){
int c = i;
int parent = HT[c].parent;
while(parent){
if(HT[parent].lchild == c){
strncat(HC[i], "0", 1);
}else{
strncat(HC[i], "1", 1);
}
c = parent;
parent = HT[parent].parent;
}
reverse(HC[i]); // 因這里是從葉節點到根節點的編碼,所以要使用reverse()函數來逆置編碼使其變為哈夫曼編碼
}
}
由於本人也是一名初學者,水平有限。這里參考了其他作者的代碼,我只是將這位作者的代碼按照自己的思路來理了一遍,希望能幫助像我一樣的初學者能更好地理解哈夫曼樹和哈夫曼編碼的代碼實現過程吧!
參考代碼來自:https://blog.csdn.net/weixin_43843978/article/details/89451845