Encoding and decoding using Huffman tree

#include<iostream>
#include<string.h>
#include<stdlib.h>
using namespace std;

typedef char** HuffmanCode;
typedef struct
{
    
    
	int s1 = 0;
	int s2 = 0;
}Num;//返回两个最小数的结构体

//哈夫曼树的结构
typedef struct {
    
    
	int weight = NULL;//权值
	char data = NULL;//结点信息
	int parent = 0, lchild = 0, rchild = 0;//双亲,左孩子,右孩子
	int sum = 1;//节点数量
}HTNode, * HuffmanTree;
//哈夫曼树的结构

Num Select(HuffmanTree HT, int range)//选择两个权值最小的节点
{
    
    
	Num n;
	while (!n.s1 || !n.s2)
	{
    
    
		Num min;
		for (int i = 1; i <= range; i++)//选择第一个没有双亲的节点
		{
    
    
			if (HT[i].parent == 0)
			{
    
    
				min.s1 = HT[i].weight;
				min.s2 = i;
				break;
			}
		}
		for (int i = 1; i <= range; i++)
		{
    
    
			if (HT[i].weight < min.s1 && HT[i].parent == 0)
			{
    
    
				min.s1 = HT[i].weight;//记录值
				min.s2 = i;
			}
		}
		HT[min.s2].parent = 1;
		if (!n.s1) {
    
     n.s1 = min.s2; }//先将权值最小的节点的序号付给n.s1
		else {
    
     n.s2 = min.s2; }
	}
	return n;
}

//构造哈夫曼树
void CreateHumanTree(HuffmanTree& HT, int n)
{
    
    
	if (n <= 1) return;
	int m = 2 * n - 1;
	HT = new HTNode[m + 1];
	for (int i = 1; i <= m; i++)//下标从1开始,初始化
	{
    
    
		HT->sum++;
		HT[i].parent = 0;
		HT[i].lchild = 0;
		HT[i].rchild = 0;
	}
	cout << "输入各节点的权值和结点信息:";
	for (int i = 1; i <= n; i++)
	{
    
    
		cin >> HT[i].weight >> HT[i].data;
	}
	for (int i = n + 1; i <= m; i++)
	{
    
    
		int s1, s2;
		Num n = Select(HT, i - 1);
		s1 = n.s1; s2 = n.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 CreateHuffmanCode(HuffmanTree HT, HuffmanCode& HC, int n)
{
    
    
	HC = new char* [n + 1];//为HC分配n+1个空间
	for (int i = 1; i <= n; i++)
	{
    
    
		char *cd = new char[n];
		cd[n - 1] = '\0';
		int start = n - 1;
		int c = i;
		int f = HT[i].parent;
		while (f)
		{
    
    
			--start;
			if (HT[f].lchild == c) 
			{
    
     cd[start] = '0'; }
			else if (HT[f].rchild == c)
			{
    
     cd[start] = '1'; }
			c = f; f = HT[f].parent;
		}
		HC[i] = new char[n - start];
		strcpy_s(HC[i], n-start,&cd[start]);
		delete []cd;
	}
	
}//5 a 29 b 7 c 8 d 14 e 23 f 3 g 11 h
//构造哈夫曼编码

//构造哈夫曼编码
void Transcode(HuffmanTree HT, string s)
{
    
    
	int len = s.length();//字符串的长度
	for (int i = 0; i < len; i++)
	{
    
    
		int j = HT->sum - 1;//哈夫曼树的根节点
		while (HT[j].lchild && HT[j].rchild)
		{
    
    
			if (s[i] == '0')//指向左子树
			{
    
    
				j = HT[j].lchild;
			}
			else//指向右子树
			{
    
    
				j = HT[j].rchild;
			}
			i++;
		}
		i--;//退一格
		cout << HT[j].data;//输出
	}
}

//求哈夫曼树的带权路径长度
int WPL(HuffmanTree HT)
{
    
    
	int sum = 0;//带权路径长度
	for (int i = 1; i <= HT->sum / 2; i++)//从第一个节点开始寻找根节点,找到路径长度
	{
    
    
		int j = 0;
		int i_ = i;
		while (HT[i_].parent)
		{
    
    
			i_ = HT[i_].parent;
			j++;//路径长度
		}
		sum += j * HT[i].weight;
	}
	return sum;
}
//求哈夫曼树的带权路径长度

int main()                                                                       
{
    
    
	HuffmanTree T;
	HuffmanCode HC;
	int n;
	string s;
	cout << "您要输入节点的个数:";
	cin >> n;
	CreateHumanTree(T,n);
	cout << "最短路径长度:" << WPL(T) << endl;
	CreateHuffmanCode(T, HC, n);
	for (int i = 1; i <= n; i++)
	{
    
    
		cout << T[i].data << ":" << HC[i] << endl;
	}
	cout << "您要翻译的编码:";
	cin >> s;
	Transcode(T, s);
	return 0;
}

Guess you like

Origin blog.csdn.net/m0_43456002/article/details/104302085