数据结构-哈夫曼编码的生成

#include <iostream>
#include <iomanip>
using namespace std;

const int N = 20;
typedef struct {
	int weight;//权值
	int parent, lchild, rchild;//双亲结点和左右孩子结点
}HTNode, * HuffmanTree;
typedef char** HuffmanCode;//二维数组存储每个叶结点的哈夫曼编码

void Select(HuffmanTree& HT, int n, int& s1, int& s2);//每次选择出权值最小的两个结点,用s1 s2返回以用来合并新结点
void CreateHuffmanTree(HuffmanTree& HT, int* w, int n);//建立哈夫曼树,结点存在与数组w中,结点个数为n
void HuffmanCoding(HuffmanTree& HT, HuffmanCode& HC, int* w, int n);//利用哈夫曼树编写哈夫曼编码,结点存在与数组w中,结点个数为n
void strcpy(char* HC, char* code, int start);//从code的第start位开始将code复制到HC
void DisplayHuffmanTree(HuffmanTree HT, int n);

void Select(HuffmanTree& HT, int n, int& s1, int& s2) {
	int min = 0;//临时变量,用于存储权值最小的元素
	for (int i = 0; i < n; i++) {//第一轮循环,寻找一个无父母的结点
		if (HT[i].parent == -1) {
			min = i; break;
		}
	}
	for (int i = min + 1; i < n; i++) {//第二轮循环,遍历min之后的所有结点,将权值最小的结点存入min
		if (HT[i].parent == -1)
			if (HT[i].weight < HT[min].weight)
				min = i;
	}
	s1 = min;//找到了第一个最小结点
	//重复上述过程,但要确保所找到元素非s1
	for (int i = 0; i < n; i++) {//第一轮循环,寻找一个无父母的结点
		if (HT[i].parent == -1 && i != s1) {
			min = i; break;
		}
	}
	for (int i = min + 1; i < n; i++) {//第二轮循环,遍历min之后的所有结点,将权值最小的结点存入min
		if (HT[i].parent == -1)
			if (HT[i].weight < HT[min].weight && i != s1)
				min = i;
	}
	s2 = min;//找到了第二个最小结点
}
void CreateHuffmanTree(HuffmanTree& HT, int* w, int n) {
	if (n <= 1)return;//如果结点为1个或不存在则直接完成建立
	int m = 2 * n - 1;//根据公式,总结点个数为2n-1个
	HT = new HTNode[m];//分配m个空间用来建立哈夫曼树
	if (!HT)exit(0);
	for (int i = 0; i < n; i++) {//前n个结点用来存储初始的所有叶子结点
		HT[i].parent = -1;
		HT[i].lchild = -1;
		HT[i].rchild = -1;
		HT[i].weight = w[i];
	}
	for (int i = n; i < m; i++) {//后面的结点用来存储哈夫曼树的非叶子结点,先进行初始化
		HT[i].parent = -1;
		HT[i].lchild = -1;
		HT[i].rchild = -1;
		HT[i].weight = 0;
	}

	for (int i = n; i < m; i++) {
		int s1, s2;
		Select(HT, i, s1, s2);//从0-i-1一共i个结点中选出最小的s1和s2
		HT[s1].parent = i;
		HT[s2].parent = i;
		HT[i].lchild = s1;
		HT[i].rchild = s2;
		HT[i].weight = HT[s1].weight + HT[s2].weight;
	}
}
void HuffmanCoding(HuffmanTree& HT, HuffmanCode& HC, int* w, int n) {
	HC = new char* [n];//一共n个结点,分配n个一维数组组成一个二维数组
	if (!HC)exit(0);
	char* code = new char[n];//编码长度不会超过结点总数
	if (!code)exit(0);
	code[n - 1] = '\0';//最后一位放\0
	for (int i = 0; i < n; i++) {
		int start = n - 1;
		for (int ch = i, fa = HT[i].parent; fa != -1; ch = fa, fa = HT[fa].parent) {
			//取首元素为初始孩子ch,令fa为其父母,若父母不存在(为叶子结点)则继续循环,循环一次后ch父母变为ch,fa为此时ch的父母
			if (HT[fa].lchild == ch)
				code[--start] = '0';//若该叶子结点为父母的左孩子,编码0,右孩子编码1
			else
				code[--start] = '1';
		}
		HC[i] = new char[n - start];
		strcpy(HC[i], code, start);
	}
	delete[] code;
}
void strcpy(char* HC, char* code, int start)
{
	int i = 0;
	while (code[start] != '\0')
	{
		HC[i] = code[start];
		i++;
		start++;
	}
	HC[i] = '\0';
}
void DisplayHuffmanTree(HuffmanTree HT, int n)
{
	int i, m;
	if (n <= 1)
		return;
	cout << "weight parent lchild rchild\n";
	m = 2 * n - 1;
	for (i = 0; i < m; i++)
		cout << setw(4) << HT[i].weight << setw(7) << HT[i].parent << setw(7) << HT[i].lchild << setw(7) << HT[i].rchild << endl;
}//DisplayHuffmanTree


int main()
{
	HuffmanTree HT;
	cout << "请输入叶子结点的个数(<=100):" << endl;
	int i, n;
	cin >> n;
	int w[N];
	cout << "请依次输入个结点的权值(为正整型值):" << endl;
	for (i = 0; i < n; i++)
		cin >> w[i];
	CreateHuffmanTree(HT, w, n);
	DisplayHuffmanTree(HT, n);
	HuffmanCode HC;
	HuffmanCoding(HT, HC, w, n);
	cout << "各个节点元素赫夫曼编码:\n";
	for (i = 0; i < n; i++) {
		cout << "第" << i + 1 << "个叶子的权重:" << w[i] << ",编码:" << HC[i] << endl;
	}
	return 0;
}

实验样例

 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜菜的大鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值