哈夫曼樹及其編碼

聽聞__發表於2018-04-24

1、定義

  • 樹的帶權路徑長度(WPL)

將樹的每一個節點附加一個權值,樹中所有葉子節點的帶權路徑長度之和成為該樹的帶權路徑長度。其計算公式如下:


  • 哈夫曼樹

帶權路徑長度WPL最小的二叉樹成為哈夫曼樹(或最優二叉樹)。

  • 哈夫曼編碼

規定哈夫曼樹種左分支為0,右分支為1,則從根節點到每個葉子節點所經過的分支對應的0和1組成的序列便為該節點對應字元的編碼,這樣的編碼成為哈夫曼編碼。

詳細定義可檢視部落格:https://blog.csdn.net/l494926429/article/details/52494926

2、應用

哈夫曼樹主要用於哈夫曼編碼,可以起到壓縮作用。

3、實現

(1)哈夫曼樹的型別定義

typedef struct HTNode
{
	char data;
	double weight;
	int parent, left, right;
}HTNode;

(2)哈夫曼樹的構造演算法

//returns the huffman tree
HTNode* CreateHTNode(char* src, double* weight, int n)
{
	int h_n = 2 * n - 1;
	//init the huffman tree
	HTNode* h = new HTNode[h_n];
	for (int i = 0; i < n; i++)
	{
		h[i].data = src[i];
		h[i].weight = weight[i];
		h[i].parent = h[i].left = h[i].right = -1;
	}
	for (int i = n; i < h_n; i++)
		h[i].parent = -1;
	//create the huffman tree
	int min1_index, min2_index; //the index of the least two weight
	for(int i = n ; i < h_n; i++)
	{
		min1_index = min2_index = -1;
		for (int j = 0; j < i; j++)
		{
			if (h[j].parent == -1)
			{
				if (min1_index == -1 || h[j].weight < h[min1_index].weight)
				{
					min2_index = min1_index;
					min1_index = j;
				}
				else if (min2_index == -1 || h[j].weight < h[min2_index].weight)
				{
					min2_index = j;
				}
			}
		}
		h[i].weight = h[min1_index].weight + h[min2_index].weight;
		h[i].left = min1_index;
		h[i].right = min2_index;
		h[min1_index].parent = h[min2_index].parent = i;
	}
	return h;
}

(3)哈夫曼編碼

//returns the huffman code of the huffman tree
map<char, string>* CreateHCode(HTNode* h, int n)
{
	map<char, string>* m = new map<char, string>;
	for (int i = 0; i < n; i++)
	{
		string t = "";
		int k = i;
		while (h[k].parent != -1)
		{
			if (h[h[k].parent].left == k)
				t += '0';
			else
				t += '1';
			k = h[k].parent;
		}
		reverse(t.begin(), t.end());
		(*m)[h[i].data] = t;
	}
	return m;
}

4、測試

        假設用於通訊的電文僅由 8 個字母組成,字母在電文中出現的頻率分別為 0.07,0.19,0.02,0.06,0.32,0.03,0.21,0.10。試為這 8 個字母設計哈夫曼編碼。

#include <iostream>
#include <string>
#include <map>
using namespace std;

typedef struct HTNode
{
	char data;
	double weight;
	int parent, left, right;
}HTNode;

//returns the huffman tree
HTNode* CreateHTNode(char* src, double* weight, int n)
{
	int h_n = 2 * n - 1;
	//init the huffman tree
	HTNode* h = new HTNode[h_n];
	for (int i = 0; i < n; i++)
	{
		h[i].data = src[i];
		h[i].weight = weight[i];
		h[i].parent = h[i].left = h[i].right = -1;
	}
	for (int i = n; i < h_n; i++)
		h[i].parent = -1;
	//create the huffman tree
	int min1_index, min2_index; //the index of the least two weight
	for(int i = n ; i < h_n; i++)
	{
		min1_index = min2_index = -1;
		for (int j = 0; j < i; j++)
		{
			if (h[j].parent == -1)
			{
				if (min1_index == -1 || h[j].weight < h[min1_index].weight)
				{
					min2_index = min1_index;
					min1_index = j;
				}
				else if (min2_index == -1 || h[j].weight < h[min2_index].weight)
				{
					min2_index = j;
				}
			}
		}
		h[i].weight = h[min1_index].weight + h[min2_index].weight;
		h[i].left = min1_index;
		h[i].right = min2_index;
		h[min1_index].parent = h[min2_index].parent = i;
	}
	return h;
}

//returns the huffman code of the huffman tree
map<char, string>* CreateHCode(HTNode* h, int n)
{
	map<char, string>* m = new map<char, string>;
	for (int i = 0; i < n; i++)
	{
		string t = "";
		int k = i;
		while (h[k].parent != -1)
		{
			if (h[h[k].parent].left == k)
				t += '0';
			else
				t += '1';
			k = h[k].parent;
		}
		reverse(t.begin(), t.end());
		(*m)[h[i].data] = t;
	}
	return m;
}

int main()
{
	const char data[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' };
	const double weight[] = {0.07, 0.19, 0.02, 0.06, 0.32, 0.03, 0.21, 0.10};
	const int n = 8;

	HTNode* h = CreateHTNode(const_cast<char*>(data), const_cast<double*>(weight), n);
	map<char, string>* m = CreateHCode(h, n);

	for (map<char, string>::iterator iter = m->begin(); iter != m->end(); iter++)
	{
		cout << iter->first << " : " << iter->second << endl;
	}

	delete []h, m;
	system("pause");
	return 0;
}

相關文章