05-树9 Huffman Codes (30 分)

解题思路:
建立哈夫曼树需要利用最小堆
先判断带权路径长度WPL是否正确
判断是否为前缀编码,即所有的字符都出现在叶节点

有几点需要注意的:
1.最小堆的建立,定义哨兵,其weight为-1,从data[1]开始存储
2.最小堆弹出根节点建立哈夫曼树,在构建哈夫曼树的时候,要注意树的规模在改变;最小堆是通过数组来存储的。
3.最小堆弹出节点的时候,先申请一块节点空间用来存储弹出来的根节点;然后将最后一个节点填充,再调整成最小堆。
4.建立哈夫曼树也需要把计算的权值Insert到最小堆。
5.判断是否为前缀编码:每次遍历完一个编码之后,就在最后一个节点立个flag;这样再有编码经过该节点,就会返回错误;如果编码没有经过上面的叶子节点,则需要通过判断是否为叶子节点来判断。哈夫曼树的所有编码节点都是叶子节点。
在这里插入图片描述

代码如下,此为历经5-6小时的结果:

#include <iostream>
#include <string>
using namespace std;
const int maxn = 64; //每个哈夫曼编码不超过63位


typedef struct TreeNode* HuffmanTree;
struct TreeNode { //定义树的结点  -- 哈夫曼树的节点
	int weight = 0;
	HuffmanTree left = NULL;
	HuffmanTree right = NULL;
};

typedef struct HeapNode* MinHeap;//对权值建立最小堆
struct HeapNode {
	TreeNode data[maxn];
	int size = 0;
};
typedef struct JNode* Newtree;//对权值建立最小堆
struct JNode {
	int Flag = 0;
	Newtree left = NULL;
	Newtree right = NULL;
};


MinHeap createHeap() {
	MinHeap H = new(HeapNode);
	H->data[0].weight = -1;  //可以是0哇???此处为哨兵
	return H;
}

bool JudgeQz(string temp, Newtree J) {
	int i = 0;
	for (; i < temp.length(); i++) {
		if (temp[i] == '0') {
			if (J->left == NULL) {
				Newtree J_1 = new(JNode);
				J->left = J_1;
			}
			else {
				if (J->left->Flag == 1) {
					return false;
				}
			}
			J = J->left;
		}
		else
		{
			if (J->right==NULL)
			{
				Newtree J_1 = new(JNode);
				J->right = J_1;
			}
			else {
				if (J->right->Flag == 1) {
					return false;
				}
			}
			J = J->right;
		}
	}
	J->Flag = 1;
	if (J->left == NULL && J->right == NULL)  //叶子结点
	{
		return true;
	}
	else {
		return false;
	}
}



HuffmanTree DeleteMin(MinHeap H) {
	
	int Parent=0, Child=0;
	TreeNode temp;
	HuffmanTree MinItem = new TreeNode;
	*MinItem  = H->data[1]; /* 取出根结点存放的最大值 */
	//cout << MinItem.weight << endl;
						  /* 用最大堆中最后一个元素从根结点开始向上过滤下层结点 */
	temp = H->data[H->size--]; /* 注意当前堆的规模要减小 */
	for (Parent = 1; Parent * 2 <= H->size; Parent = Child) {
		Child = Parent * 2;
		if ((Child != H->size) && (H->data[Child].weight > H->data[Child + 1].weight))
			Child++;  /* Child指向左右子结点的较小者 */
		if (temp.weight <= H->data[Child].weight) break; /* 找到了合适位置 */
		else  /* 下滤X */
			H->data[Parent] = H->data[Child];
	}
	H->data[Parent] = temp;

	return MinItem;
}
void Insert(MinHeap H, HuffmanTree T) {
	int i = ++(H->size);
	for ( ;H->data[i/2].weight>T->weight; i/=2)
	{
		H->data[i] = H->data[i / 2];
	}
	H->data[i] = *T;
	//cout << T->weight << endl;
}

HuffmanTree Huffman(MinHeap H) { //构建haffman树
	int i;
	HuffmanTree T = NULL;
	int num = H->size;   //size的规模在改变
	for (i = 1; i < num; i++) {
		T = new TreeNode;
		T->left = DeleteMin(H);
		T->right = DeleteMin(H);

		T->weight = T->left->weight + T->right->weight;
		//cout << T->left->weight <<"left"<< T->right->weight << endl;
		//cout << T->weight << endl;
		Insert(H, T);
	}
	T = DeleteMin(H);
	return T;
}

int WPL(HuffmanTree T, int depth) {
	if ((T->left == nullptr) && (T->right == nullptr))
		return depth*(T->weight);
	else
		return (WPL(T->left, depth + 1) + WPL(T->right, depth + 1));
}

MinHeap ReadData(int N, MinHeap H, int Value[]) {
	char s = '\0';
	int value = 0;
	for (int i = 0; i < N; i++) {
		cin >> s;
		cin >> value;
		Value[i] = value;
		HuffmanTree T = new(TreeNode);
		T->weight = value;
		Insert(H, T);
	}
	return H;
}


int main() {
	int N = 0, n = 0;//分别是编码字母的个数和读入的次数
	cin >> N;
	MinHeap H = createHeap();
	int Value[maxn] = {};//
	H = ReadData(N, H, Value);  //已经建立了最小堆
	/*cout<< H->data[1].weight << endl;
	cout << H->data[2].weight << endl;
	cout << H->data[3].weight << endl;
	cout << H->data[4].weight << endl;
	cout << H->data[5].weight << endl;
	cout << H->data[6].weight << endl;
	cout << H->data[7].weight << endl;*/
	
	HuffmanTree T = Huffman(H);
	//cout << T->weight;
	

	int wpl = WPL(T,0);
	//cout << wpl << endl;

	cin >> n;
	string temp = "\0";
	char c = '\0';
	bool result = false;

	for (int i = 0; i < n; i++)
	{		
		int coreWpl = 0,flag = 0;
		Newtree J = new JNode;
	
		for (int j = 0; j < N; j++)
		{
			cin >> c>> temp;
			if (temp.length() > N - 1) result = false;
			coreWpl += temp.length()*Value[j];
			if (flag==0)
			{
				result = JudgeQz(temp, J);
				if (result==false)
				{
					flag = 1;
				}
			}
		}
		delete J;
		//cout << coreWpl << endl;
		if (result && (coreWpl == wpl))
		{
			cout << "Yes" << endl;
		}
		else {
			cout << "No" << endl;
		}
	}

	system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值