进阶实验4-3.5 哈夫曼编码

题目链接
简要思路:
1.首先,我们需要自己建一棵哈夫曼树,这里我们用到了自己写的最小堆,也可以用STL里的优先队列,从最小堆中每次取出两个权值最小的元素,将它们合并,并插入原堆中,重复该操作直到堆中只剩一个元素,说明建树完成。
2.用read函数遍历求取最小字节,遍历哈夫曼树,读到两边都为nullptr的即是作为叶子节点的字符结点。
3.计算样例中字节总长度和其单字符最长的字节长度,总长度必须等于最小字节,最长字节长度小于编码字符数N,才进入下一步判断。
4.进一步的判断是样例中的哈夫曼树能否建成,若存在两个字符的编码拥有相同前缀,会造成歧义,我建树是从nullptr开始,让每个编码开辟路径,当前为‘0’则向左建,向右反之,如若用当前编码建到尽头发现左右不为nullptr,说明有编码开辟过到后面去了,这个编码是某个编码前缀,返回false。又或者说当前编码开辟到某处发现这里已经存在编码到这里的字符了,说明有字符的编码是当前字符编码的前缀,也返回false.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int MAX = 64;
int bitsum;//最小字节长度
int Size = 0;//最小堆的size
char name[64][64];//存样例的编码
struct Huffman {
	bool exist;
	int sum;
	Huffman* left, * right;
	Huffman() { left = right = nullptr; exist = 0; }
}*head;
int frequency[128];//存字符出现频数
Huffman* MinHeap[64];
void Insert(Huffman* target);//结点插入最小堆
Huffman* Delete();//从最小堆中删除结点
void read(Huffman*head,int depth);//求取哈夫曼树字节长度
bool Create_Huffman_Tree(Huffman*& head,char code[],int pos);//试建哈夫曼树
Huffman* Create();
int main() {
	int N,a;
	char c;
	bool f = true;
	Huffman* head;
	scanf("%d", &N);
	for (int i = 0; i < N; i++) {
		Huffman *t=new Huffman;
		scanf(" %c%d", &c,&t->sum);
		Insert(t);
		frequency[c - '0'] = t->sum;
	}
	int K;
	head = Create();
	read(head,0);
	scanf("%d", &K);
	while (K--) {
		char count[1000];
		int s=0, k = 0,i,maxcount=-1,cnt;
		Huffman* H=nullptr;
		f = true;
		for (i = 0; i < N; i++) {
			scanf(" %c%s", &c, count);
			cnt= strlen(count);
			s += cnt*frequency[c-'0'];
			if (cnt > maxcount)
				maxcount = cnt;
			strcpy(name[k++], count);
		}
		if (s != bitsum || maxcount > N - 1)
			f = false;
		else {
			for (i = 0; i < k; i++)
				if (!Create_Huffman_Tree(H, name[i], 0))
					break;
			if (i != k)
				f = false;
		}
		if (f)
			printf("Yes\n");
		else
			printf("No\n");
		delete[]H;
		H = nullptr;
	}
}
void Insert(Huffman* target) {
	int i;
	Size++;
	for (i = Size; i != 1 && MinHeap[i / 2]->sum > target->sum; i /= 2)
		MinHeap[i] = MinHeap[i / 2];
		MinHeap[i] = target;
}
Huffman* Delete() {
	Huffman* Min = MinHeap[1];
	Huffman* temp = MinHeap[Size--];
	int parent, child;
	for (parent = 1; parent * 2 <= Size; parent = child) {
		child = parent * 2;
		if (child != Size && MinHeap[child + 1]->sum < MinHeap[child]->sum)//child!=Size表示右儿子存在,因为左儿子位置已经小于等于Size了
			child++;
		if (temp->sum > MinHeap[child]->sum)
			MinHeap[parent] = MinHeap[child];
		else
			break;
	}
	MinHeap[parent] = temp;
	return Min;
}
void read(Huffman* head,int depth) {
	if (head->left == nullptr && head->right == nullptr) {
		bitsum += head->sum * depth;
		return;
	}
	if (head->left)
		read(head->left, depth + 1);
	if (head->right)
		read(head->right, depth + 1);
}
bool Create_Huffman_Tree(Huffman*& head,char code[], int pos) {
	bool f1=true, f2=true;
	if (head == nullptr)
		head = new Huffman;
	else if (head->exist)
		return false;
	if (!code[pos]) {
		if (head->exist || head->left != nullptr || head->right != nullptr)
			return false;
		head->exist = true;
	}
	else if (code[pos] == '0')
		f1=Create_Huffman_Tree(head->left, code,pos+1);
	else if (code[pos] == '1')
		f2=Create_Huffman_Tree(head->right, code, pos + 1);
	return (f1&&f2);
}
Huffman* Create() {
	Huffman* link=new Huffman;
	while (Size != 1) {
		link = new Huffman;
		Huffman* t1 = Delete(), * t2 = Delete();
		link->left = t1;
		link->right = t2;
		link->sum = t1->sum + t2->sum;
		Insert(link);
	}
	return link;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值