05-树9 Huffman Codes

05-树9 Huffman Codes (30分)

题目描述

In 1953, David A. Huffman published his paper “A Method for the Construction of Minimum-Redundancy Codes”, and hence printed his name in the history of computer science. As a professor who gives the final exam problem on Huffman codes, I am encountering a big problem: the Huffman codes are NOT unique. For example, given a string “aaaxuaxz”, we can observe that the frequencies of the characters ‘a’, ‘x’, ‘u’ and ‘z’ are 4, 2, 1 and 1, respectively. We may either encode the symbols as {‘a’=0, ‘x’=10, ‘u’=110, ‘z’=111}, or in another way as {‘a’=1, ‘x’=01, ‘u’=001, ‘z’=000}, both compress the string into 14 bits. Another set of code can be given as {‘a’=0, ‘x’=11, ‘u’=100, ‘z’=101}, but {‘a’=0, ‘x’=01, ‘u’=011, ‘z’=001} is NOT correct since “aaaxuaxz” and “aazuaxax” can both be decoded from the code 00001011001001. The students are submitting all kinds of codes, and I need a computer program to help me determine which ones are correct and which ones are not.

Input Specification

Each input file contains one test case. For each case, the first line gives an integer N (2 ≤ N ≤ 63), then followed by a line that contains all the N distinct characters and their frequencies in the following format:

c[1] f[1] c[2] f[2] ... c[N] f[N]

where c[i] is a character chosen from {‘0’ - ‘9’, ‘a’ - ‘z’, ‘A’ - ‘Z’, ‘_’}, and f[i] is the frequency of c[i] and is an integer no more than 1000. The next line gives a positive integer M (≤1000), then followed by M student submissions. Each student submission consists of N lines, each in the format:

c[i] code[i]

where c[i] is the i-th character and code[i] is an non-empty string of no more than 63 '0’s and '1’s.

Output Specification

For each test case, print in each line either “Yes” if the student’s submission is correct, or “No” if not.

Note: The optimal solution is not necessarily generated by Huffman algorithm. Any prefix code with code length being optimal is considered correct.

Sample Input

7
A 1 B 1 C 1 D 3 E 3 F 6 G 6
4
A 00000
B 00001
C 0001
D 001
E 01
F 10
G 11
A 01010
B 01011
C 0100
D 011
E 10
F 11
G 00
A 000
B 001
C 010
D 011
E 100
F 101
G 110
A 00000
B 00001
C 0001
D 001
E 00
F 10
G 11

Sample Output

Yes
Yes
No
No

解题思路

本题的大意是:由于哈夫曼编码的不唯一性,从 WPL 的角度,最优编码的个数可以有多个,我们现在需要判断输入的编码是否是可能的一种最优编码类型。
例如,对于题目中所给出的测试案例,以下两种哈夫曼编码类型都是可能的:

1

两棵树的 WPL 均为53.

最小堆的实现

哈夫曼树的创建的前提是需要一个最小堆,代码如下:

// 哈夫曼树结点定义
typedef struct HuffmanTree {
   
    int frequency; // 表示每个字符出现的频率
    struct HuffmanTree *left;
    struct HuffmanTree *right;
} HuffmanTree;

#define root 0 // 初始化堆的根结点为0
#define parent(idx) ( idx / 2 ) // 查找idx的父结点索引
#define lchild(idx) ( idx * 2 + 1 ) // 查找idx的左孩子结点索引
#define rchild(idx) ( idx * 2 + 2 ) // 查找idx的右孩子结点索引

// 最小堆的定义
typedef struct Heap {
   
    HuffmanTree **data; // 存储值类型为HuffmanTree的数组
    int size; // 结点的个数
    int capacity; // 堆的最大容量
} MinHeap;

// 创建及初始化最小堆
MinHeap *CreateHeap( int size ) {
   
    MinHeap *heap = ( MinHeap *) malloc(sizeof(MinHeap) );
    heap->data = ( HuffmanTree **) malloc(sizeof(HuffmanTree *) * size );
    heap->size = 0;
    heap->capacity = size;
    return heap;
}

// 父子结点的交换,直接进行结点的交换
void swap( MinHeap *heap, int idx1, int idx2 ) {
   
    HuffmanTree *temp = heap->data[idx1];
    heap->data[idx1] = heap->data[idx2];
    heap->data[idx2] = temp;
}

// 父子结点的比较,比较的依据是frequency
bool compare(MinHeap *heap, int idx1, int idx2 ) {
   
    return heap->data[idx1]->frequency < heap->data[idx2]->frequency;
}

// 堆的上浮操作,通常用于向堆中插入元素,进行结点的调整
void Heap_Float(MinHeap *heap, int idx ) {
   
    int par = parent(idx);
    while ( par >= root ) {
   
        // 如果当前结点大于其父结点,进行交换
        if ( compare(heap, idx, par) ) {
   
            swap(heap, par, idx);
            idx = par;
            par = parent(idx);
        }
        else break;
    }
}

// 判断堆是否已满
bool isFull(MinHeap *heap ) {
   
    return heap->size == heap->capacity;
}

// 向堆中插入元素,与堆栈类似,不过需要进行值的上浮操作
bool Heap_Push(MinHeap *heap, HuffmanTree *val ) {
   
    if ( isFull(heap) ) {
   
        return false;
    }
    heap->data[heap->size ++] = val;
    Heap_Float(heap, heap->size - 1);
    return true;
}

// 堆的下沉操作,通常用于向堆中删除元素,进行结点的调整
void Heap_Sink(MinHeap *heap, int idx ) {
   
    int child = lchild(idx);
    while ( child <</
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值