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.

题意:

每个输入文件包含一个测试用例。对于每种情况,第一行给出一个整数N (2≤N≤63),然后后跟一行包含所有N不同的字符及其频率。下一行给出一个正整数M (≤1000),然后接着是M学生提交的材料。每个学生提交的作品包括N行

思路:

进行哈夫曼编码时用优先队列存储指向结构体的指针(或者可以用暴力每次找最小的两个)

然后先计算最短码长,与学生的进行比较,若相同则检查学生的是否是前缀码

#include <bits/stdc++.h>
using namespace std;
map<string,int>ma;		//便于计算学生的最短码长 
int ans = 0;
struct node {			//进行哈夫曼编码的node 
    string s;		
    int fre;
    node* l;
    node* r;
    int h;
};
struct CompareNodePointers {
    bool operator()(const node* a, const node* b) const {
        return a->fre > b->fre;
    }
};
struct nodet {			//进行测试学生的nodet
	string s,ss;		//s是字符,ss是学生的编码
};
node* in(node* j, node* k) {
    node* t = new node; 
    t->l = j;
    t->r = k;
    t->fre  = j->fre +k->fre ;
    return t;
}
void check(node *t){
	if(t->l && t->r ){
		ans+=t->fre ;
		check(t->l );
		check(t->r );
	}
}
int main() {
    int n,m;
    cin >> n;
    node a[n + 1];
    priority_queue<node*, vector<node*>, CompareNodePointers> q;
    for (int i = 1; i <= n; i++) {
        cin >> a[i].s >> a[i].fre;
        a[i].l  = a[i].r  = NULL;
        ma[a[i].s ] = a[i].fre ;
        node* aa = &a[i];
        q.push(aa);
    }
    node* t;
    while (q.size() > 1) {
        node* j = q.top();
        q.pop();
        node* k = q.top();
        q.pop();
        t = in(j, k);
        if(!q.empty())q.push(t);
    }
	check(t);		//计算最短码长 
	cin>>m;
	while(m--){
		int anss = 0;
		vector<nodet>test;
		for(int i = 1;i<=n;i++){
			nodet j;
			cin>>j.s >>j.ss ;
			anss+=j.ss.length() * ma[j.s]; 
			test.push_back(j);
		}
		int flag = 1;
		if(anss != ans)flag = 0;
		for (int i = 0; i < test.size(); ++i) {
        	for (int j = 0; j < test.size(); ++j) {
        		string o,p;
        		o = test[j].ss;
        		p = test[i].ss;
            	if (i != j && o.find(p) == 0) {
                	flag = 0; // 找到某个编码是另一个编码的前缀
                	break;
            	}
        	}
    	}
		if(flag)cout<<"Yes"<<endl;
		else cout<<"No"<<endl;
	}
    return 0;
}

<think>好的,我现在需要回答用户关于哈夫曼及哈夫曼编码的实现问题,特别是SelectTwoMin和HuffmanCoding函数的功能与用法,还提到浙江大学wgy的相关内容。首先,我得回顾一下哈夫曼的基本概念和构建步骤,确保自己对基础知识的理解正确。 哈夫曼是一种带权路径长度最短的二叉,常用于数据压缩。构建过程通常包括选择权重最小的两个节点合并,直到形成一棵。用户提到的SelectTwoMin函数应该就是用来选择当前未处理的节点中权重最小的两个,这一步是关键,因为每次合并都会生成新的节点,影响整个的结构。 接下来是HuffmanCoding函数,这个函数的作用应该是根据构建好的哈夫曼生成每个叶子节点的编码。通常是从叶子节点回溯到根节点,左路径为0,右路径为1,然后将编码反转,因为回溯得到的顺序是相反的。用户可能对如何具体实现这个编码过程感兴趣,特别是如何处理路径的记录和反转。 根据用户提供的引用内容,引用[1]提到哈夫曼的节点数为2n-1,使用数组存储,每个节点包含父子信息,形成静态三叉链表。这可能涉及到节点的数据结构定义,比如权重、父节点、左右子节点的索引。SelectTwoMin函数需要遍历数组,找到两个权重最小且未被合并的节点,这一步的时间复杂度如果是O(n^2),可能如引用[3]所说,每次扫描整个数组,导致较高的时间复杂度。不过通常可以使用优先队列来优化,但用户的问题中没有提到优化,可能更关注基础实现。 然后,HuffmanCoding函数需要从每个叶子节点向上遍历到根节点,记录路径方向。例如,左子节点为0,右为1。由于是从下到上遍历,得到的编码是逆序的,需要反转。引用[1]和[2]都提到了这一点,所以实现时要注意反转操作。 用户提到浙江大学wgy,可能是指某个课程或教材中的具体实现方式。虽然引用中没有直接提到,但需要确保回答符合常见的教学实现,比如使用数组结构,手动实现SelectTwoMin而不是使用优先队列,以符合教学目的。 现在需要组织回答的结构,首先解释哈夫曼的构建步骤,然后分别详细说明SelectTwoMin和HuffmanCoding的功能和实现方式。代码部分需要用Python示例,并且符合格式要求,比如行内公式用$...$,独立公式用$$...$$。同时,需要生成相关问题,并正确引用提供的资料。 需要注意的是,用户的问题中的引用内容可能不完全相关,比如引用[3]提到构造哈夫曼的时间复杂度为O(n^2),而常规的优先队列实现是O(n log n),但这里可能是指特定的实现方式,所以需要说明这一点。同时,在代码示例中,如何用数组表示节点,如何选择最小的两个节点,如何合并生成新节点,这些步骤都需要详细说明。 可能遇到的疑问点包括:如何确保每次选择的是未被处理的最小节点?在数组中如何标记已处理的节点?例如,可以通过父节点是否为-1或其他标记来判断节点是否已经被合并。此外,编码时如何从叶子回溯到根,需要记录路径,并在最后反转字符串。 需要确认提供的引用是否正确支持这些步骤。引用[1]和[2]提到使用数组存储节点,每个节点有父、左、右的索引,这符合静态三叉链表的描述。因此,在代码实现中,每个节点应包含这些属性。 总结回答的结构: 1. 哈夫曼的基本概念和构建步骤。 2. SelectTwoMin函数的功能和实现细节,包括遍历数组寻找最小两个节点。 3. HuffmanCoding函数的功能,如何从叶子到根生成编码并反转。 4. 代码示例,展示节点结构、SelectTwoMin的实现和编码过程。 5. 相关问题生成,涉及时间复杂度、优化方法、应用场景等。 同时,确保回答符合用户的要求,如使用中文,正确引用标记,代码格式正确,以及生成相关问题。需要检查是否有遗漏的部分,比如哈夫曼编码的具体应用,或者浙江大学wgy是否有特定的实现方式需要提及,但由于引用中没有相关信息,可能无法深入,只能基于提供的引用回答。</think>### 哈夫曼及哈夫曼编码实现详解 #### 1. 哈夫曼构建原理 哈夫曼是带权路径长度最短的二叉,构建步骤如下: 1. 将$n$个带权节点视为独立的 2. 每次选择权重最小的两个子合并,新权重为两者之和 3. 重复合并直到只剩一棵 $$WPL = \sum_{i=1}^{n} w_i \times l_i$$ 其中$w_i$为叶节点权重,$l_i$为路径长度[^1] #### 2. SelectTwoMin函数实现 **功能**:从当前未合并的节点中选取两个最小权重的节点 **实现步骤**: 1. 遍历节点数组,筛选出`parent == -1`的可用节点 2. 记录最小权重节点`min1`和次小权重节点`min2` 3. 时间复杂度为$O(n)$,整体构造过程为$O(n^2)$[^3] **代码示例**: ```python def select_two_min(nodes, n): min1 = min2 = -1 for i in range(n): if nodes[i].parent == -1: if min1 == -1 or nodes[i].weight < nodes[min1].weight: min2 = min1 min1 = i elif min2 == -1 or nodes[i].weight < nodes[min2].weight: min2 = i return min1, min2 ``` #### 3. HuffmanCoding函数实现 **功能**:从叶节点回溯生成哈夫曼编码 **实现步骤**: 1. 从叶节点向根节点回溯 2. 左路径标记为0,右路径标记为1 3. 反转编码字符串(回溯产生逆序) 4. 编码长度不超过$n-1$(的高度)[^2] **代码示例**: ```python def huffman_coding(nodes, n): codes = [&#39;&#39;] * n for i in range(n): current = i parent = nodes[current].parent while parent != -1: if nodes[parent].left == current: codes[i] = &#39;0&#39; + codes[i] else: codes[i] = &#39;1&#39; + codes[i] current = parent parent = nodes[current].parent return codes ``` #### 4. 完整数据结构定义(Python实现) ```python class Node: def __init__(self, weight=0, parent=-1, left=-1, right=-1): self.weight = weight # 节点权重 self.parent = parent # 父节点索引 self.left = left # 左子节点索引 self.right = right # 右子节点索引 def create_huffman_tree(weights): n = len(weights) nodes = [Node() for _ in range(2*n-1)] # 初始化叶节点 for i in range(n): nodes[i].weight = weights[i] # 构建哈夫曼 for i in range(n, 2*n-1): min1, min2 = select_two_min(nodes, i) nodes[min1].parent = nodes[min2].parent = i nodes[i].left = min1 nodes[i].right = min2 nodes[i].weight = nodes[min1].weight + nodes[min2].weight return nodes ``` #### 5. 浙江大学wgy实现特点 浙江大学数据结构课程实现强调: - 使用静态三叉链表存储(数组实现) - 显式维护父子关系索引 - 通过索引操作代替指针 - 编码生成时采用自底向上回溯
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值