8609 哈夫曼树
时间限制:1000MS 代码长度限制:10KB
提交次数:3178 通过次数:1263
题型: 编程题 语言: G++;GCC
Description 利用静态链表建立赫夫曼树,建树过程中要求左子树权值小于右子树权值,求各结点的编码。要求:叶子结点的个数n及结点值由键盘录入。本题给出程序代码,要求修改以满足测试要求.
思路
n个节点 会合并n-1次最后存在2n-1个节点
先找到节点里最小的两个 然后合并成新节点
重复操作 直到合成为一颗二叉树
这个oj题代码模版给的乱七八糟
有两个版本
这个是填满模版 能够查看测试的版本
#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<iostream>
#include<vector>
#include<string.h>
#include<algorithm>
#include<queue>
#include "stdio.h"
#include "malloc.h"
#include "string.h"
using namespace std;
typedef struct {
unsigned int weight;
unsigned int parent, lchild, rchild;
}HTNode, * HuffmanTree;
typedef char** HuffmanCode;
void Select(HuffmanTree HT, int n, int& s1, int& s2)
//在HT[1..n]中选择parent为0且weight最小的两个结点,
// 其序号分别为s1和s2。
{
int i;
s1 = s2 = 0;
HT[0].weight = 1e9;
for (int i = 1; i <= n; i++) {
//如果没有该节点被合并 即父节点为0
//找 两个最小的 s1 s2 s1要小于s2
if(HT[i].parent == 0){
//迭代赋值
if (HT[i].weight < HT[s1].weight) {
s2 = s1;
s1 = i;
}
else if (HT[i].weight < HT[s2].weight) {
s2 = i;
}
}
}
}
void HuffmanCoding(HuffmanTree & HT, HuffmanCode & HC, int* w, int n){
// 并求出n个字符的哈夫曼编码HC
int i, j, m, s1, s2, start;
char* cd;
unsigned int c, f;
//如果节点数小于等于一 说明已合并
if (n <= 1) return;
//n个节点 合并n-1次 最终得到2*n-1个节点
m = 2 * n - 1;
//因为下标从1开始用 所以申请 m+1 内存空间
HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode)); // 0号单元未用
//原有的节点初始化
for (i = 1; i <= n; i++) { //初始化
//初始化权值
HT[i].weight = w[i - 1];
HT[i].parent = 0;
HT[i].lchild = 0;
HT[i].rchild = 0;
}
//新合并的节点初始化 权值为0
for (i = n + 1; i <= m; i++) { //初始化
HT[i].weight = 0;
HT[i].parent = 0;
HT[i].lchild = 0;
HT[i].rchild = 0;
}
printf("\n哈夫曼树的构造过程如下所示:\n");
printf("HT初态:\n 结点 weight parent lchild rchild");
for (i = 1; i <= m; i++)
printf("\n%4d%8d%8d%8d%8d", i, HT[i].weight,
HT[i].parent, HT[i].lchild, HT[i].rchild);
printf(" 按任意键,继续 ...");
//getch()为输入一个字符,但是不显示,需要加头文件conio
getch();
//建树 新节点从n+1到m
for (i = n + 1; i <= m; i++) { // 建哈夫曼树
// 在HT[1..i-1]中选择 parent为0 且 weight最小 的 两个结点,
// 其序号分别为s1和s2。
Select(HT, i - 1, s1, s2);
//两节点父节点即为 i
HT[s1].parent = i; HT[s2].parent = i;
//小的为左子树 大的为右子树
HT[i].lchild = s1; HT[i].rchild = s2;
//新的节点i的权值即为 两子树权值之和
HT[i].weight = HT[s1].weight + HT[s2].weight;
printf("\nselect: s1=%d s2=%d\n", s1, s2);
printf(" 结点 weight parent lchild rchild");
//从1到i再次查看树的构建
for (j = 1; j <= i; j++)
printf("\n%4d%8d%8d%8d%8d", j, HT[j].weight, HT[j].parent, HT[j].lchild, HT[j].rchild);
printf(" 按任意键,继续 ...");
getch();
}
//--- 从叶子到根 逆向 求每个字符的哈夫曼编码 ---
cd = (char*)malloc(n * sizeof(char)); // 分配求编码的工作空间
cd[n - 1] = '\0'; // 编码结束符。
for (i = 1; i <= n; ++i) { // 逐个字符求哈夫曼编码
start = n - 1; // 编码结束符位置
for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent)
// 从叶子到根逆向求编码
if (HT[f].lchild == c) cd[--start] = '0';
else cd[--start] = '1';
HC[i] = (char*)malloc((n - start) * sizeof(char));
// 为第i个字符编码分配空间
strcpy(HC[i], &cd[start]); // 从cd复制编码(串)到HC
}
free(cd); //释放工作空间
} //HuffmanCoding
int main(void)
{
int i, n;
int* w;
HuffmanTree HT;
HuffmanCode HC;
printf("Node Number:");
scanf("%d", &n); //权值个数
w = (int*)malloc(n * sizeof(int));
printf("Input weights:");
for (i = 0; i < n; i++) //录入权值
scanf("%d", &w[i]);
HC = (char**)malloc((n + 1) * sizeof(char*)); //0空间未用
HT = (HuffmanTree)malloc((2 * n + 1 + 1) * sizeof(HTNode));//0空间未用
HuffmanCoding(HT, HC, w, n);
printf("\n");
for (i = 1; i < n + 1; i++) {
puts(HC[i]); //输出哈夫曼编码
free(HC[i]); //释放空间
}
free(HC);
free(HT);
return 0;
}//main
这个是根据题设的 输入输出 的模版 少了查看数据过程的代码
#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<iostream>
#include<vector>
#include<string.h>
#include<algorithm>
#include<queue>
#include "stdio.h"
#include "malloc.h"
#include "string.h"
using namespace std;
typedef struct {
unsigned int weight;
unsigned int parent, lchild, rchild;
}HTNode, * HuffmanTree;
typedef char** HuffmanCode;
void Select(HuffmanTree HT, int n, int& s1, int& s2)
//在HT[1..n]中选择parent为0且weight最小的两个结点,
// 其序号分别为s1和s2。
{
int i;
s1 = s2 = 0;
HT[0].weight = 1e9;
for (int i = 1; i <= n; i++) {
//如果没有该节点被合并 即父节点为0
//找 两个最小的 s1 s2 s1要小于s2
if(HT[i].parent == 0){
//迭代赋值
if (HT[i].weight < HT[s1].weight) {
s2 = s1;
s1 = i;
}
else if (HT[i].weight < HT[s2].weight) {
s2 = i;
}
}
}
}
void HuffmanCoding(HuffmanTree & HT, HuffmanCode & HC, int* w, int n){
// 并求出n个字符的哈夫曼编码HC
int i, j, m, s1, s2, start;
char* cd;
unsigned int c, f;
//如果节点数小于等于一 说明已合并
if (n <= 1) return;
//n个节点 合并n-1次 最终得到2*n-1个节点
m = 2 * n - 1;
//因为下标从1开始用 所以申请 m+1 内存空间
HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode)); // 0号单元未用
//原有的节点初始化
for (i = 1; i <= n; i++) { //初始化
//初始化权值
HT[i].weight = w[i - 1];
HT[i].parent = 0;
HT[i].lchild = 0;
HT[i].rchild = 0;
}
//新合并的节点初始化 权值为0
for (i = n + 1; i <= m; i++) { //初始化
HT[i].weight = 0;
HT[i].parent = 0;
HT[i].lchild = 0;
HT[i].rchild = 0;
}
//建树 新节点从n+1到m
for (i = n + 1; i <= m; i++) { // 建哈夫曼树
// 在HT[1..i-1]中选择 parent为0 且 weight最小 的 两个结点,
// 其序号分别为s1和s2。
Select(HT, i - 1, s1, s2);
//两节点父节点即为 i
HT[s1].parent = i; HT[s2].parent = i;
//小的为左子树 大的为右子树
HT[i].lchild = s1; HT[i].rchild = s2;
//新的节点i的权值即为 两子树权值之和
HT[i].weight = HT[s1].weight + HT[s2].weight;
}
//--- 从叶子到根 逆向 求每个字符的哈夫曼编码 ---
cd = (char*)malloc(n * sizeof(char)); // 分配求编码的工作空间
cd[n - 1] = '\0'; // 编码结束符。
for (i = 1; i <= n; ++i) { // 逐个字符求哈夫曼编码
start = n - 1; // 编码结束符位置
for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent)
// 从叶子到根逆向求编码
if (HT[f].lchild == c) cd[--start] = '0';
else cd[--start] = '1';
HC[i] = (char*)malloc((n - start) * sizeof(char));
// 为第i个字符编码分配空间
strcpy(HC[i], &cd[start]); // 从cd复制编码(串)到HC
}
free(cd); //释放工作空间
} //HuffmanCoding
int main(void)
{
int i, n;
int* w;
HuffmanTree HT;
HuffmanCode HC;
scanf("%d", &n); //权值个数
w = (int*)malloc(n * sizeof(int));
for (i = 0; i < n; i++) //录入权值
scanf("%d", &w[i]);
HC = (char**)malloc((n + 1) * sizeof(char*)); //0空间未用
HT = (HuffmanTree)malloc((2 * n + 1 + 1) * sizeof(HTNode));//0空间未用
HuffmanCoding(HT, HC, w, n);
for (i = 1; i < n + 1; i++) {
puts(HC[i]); //输出哈夫曼编码
free(HC[i]); //释放空间
}
free(HC);
free(HT);
return 0;
}//main