哈夫曼树的基本概念及创建(c/c++)

一、一些基本概念

1、路径:从树中一个结点到另一个结点之间的分支构成这两个结点之间的路径。
2、路径长度:路径上的分支数目称作路径长度。
3、树的路径长度:从树根到每一结点的路径长度之和。
4、权:赋予某个实体的一个量,是对实体的某个或某些属性的数值化描述。
5、结点的带权路径长度:从该结点到树根之间的路径长度与结点上权的乘积。
6、树的带权路径长度:树中所有叶子结点的带权路径长度之和,通常记为:
在这里插入图片描述
7、哈夫曼树:假设有m个权值{w1,w2,…,wm},可以构造一棵含n个叶子结点的二叉树,每个叶子结点的权为wi,则其中带权路径长度WPL最小的二叉树称为最优二叉树或哈夫曼树。
注意:
(1)完全二叉树不一定是哈夫曼树;
(2)权值越大的结点越靠近根结点;
(3)哈夫曼树不唯一,但其树的带权路径长度一定相等;

二、构造哈夫曼树

哈夫曼树结点结构:
在这里插入图片描述
哈夫曼树的存储表示

typedef struct{
 int weight;  //结点的权值
 int parent,lchild,rchild;  //结点的双亲、左孩子、右孩子的下标
}HTNode,*HuffmanTree;  //动态分配数组存储哈夫曼树

哈夫曼树结点个数:
在这里插入图片描述

例题:已知w=(5,29,7,8,14,23,3,11),生成一棵哈夫曼树,计算树的带权路径长度。并给出其构造过程中存储结构HT的初始状态和终结状态。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
【算法描述】

void CreateHT(HuffmanTree &HT,int n)
{
  if(n<=1)return ;
  m=2*n-1;
  HT=new HTNode[m+1];
  for(i=1;i<=m;++i)    //将1-m号单元的父结点、左孩子、右孩子的下标都初始化为0
   {
     HT[i].parent=0;
     HT[i}.lchild=0;
     HT[i}.rchild=0;
   }
  for(i=1;i<=n;++i)  //输入前n个结点的权值
   {
      cin>>HT[i].weight;
   }
  for(i=n+1;i<=m;++i)
  { //通过n-1次的选择、删除、合并来创建哈夫曼树
    Select(HT,i-1,s1,s2);
    //在HT[k](1<=k<=i-1)中选择两个其双亲域为0且权最小的结点,并返回他们在HT中的序号s1和s2
    HT[s1}.parent=i;
    HT[s2}.parent=i;
    //得到新结点i,从森林中删除s1,s2,将s1和s2的双亲域由0改为1
    HT[i].lchild=s1;   //s1作为i的左结点
    HT[i}.rchild=s2;  //s2作为i的右结点
    HT[i].weight=HT[s1].weight+HT[s2].weight;  //i的权值为左右孩子权值之和
  }

三、哈夫曼编码

将树的左分支标记为0,右分支标记为1;(左0右1)
在这里插入图片描述

哈夫曼编码
50 0 0 0
30 0 0 1
110 0 1
230 1
291 0
141 1 1
71 1 0 0
81 1 0 1

四、哈夫曼树的创建

要求:
1、从键盘输入n, 以及n个字符的概率。
例如:已知某系统在通信联络中只可能出现n种字符,其概率分别为 0.05, 0.29, 0.07, 0.08, 0.14, 0.23, 0.03, 0.11,试设计哈夫曼编码创建哈夫曼树。
2、用顺序存储。

#include<iostream>
using namespace std;
//哈夫曼树的存储结构
typedef struct {
	int weight;  //结点的权重
	int parent, lchild, rchild;  //结点的双亲、左孩子、右孩子的下标
}HTNode,*HuffmanTree;
//封装两个最小结点
typedef struct {
	int s1;
	int s2;
}MIN;
//选择双亲为0且结点权值最小的两个结点
MIN Select(HuffmanTree HT, int n)
{
	int min, secmin,s1,s2;
	min = 10000;
	secmin = 10000;
	MIN code;
	s1 = 1; s2 = 1;
	for (int i = 1; i <= n; i++)
	{
		if (HT[i].parent == 0 && (HT[i].weight<min))
		{
			min = HT[i].weight;
			s1 = i;
		}
	}
	for (int i = 1; i <= n; i++)
	{
		if (HT[i].parent == 0 && (HT[i].weight<secmin) && (i != s1))
		{
			secmin = HT[i].weight;
			s2 = i;
		}
	}
	code.s1 = s1;
	code.s2 = s2;
	return code;

}
//创造哈夫曼树
void CreateHuffmanTree(HuffmanTree &HT, int num)
{
	
	int m;
	m = 2 * num - 1;
	HT = new HTNode[m + 1];
	for (int i = 1; i <= m; i++)
	{
		HT[i].parent = 0;
		HT[i].lchild = 0;
		HT[i].rchild = 0;
	}
	cout << "请输入每个叶子结点的权值:" << endl;
	for (int i = 1; i <= num; i++)
	{
		cin >> HT[i].weight;
	}
	
	for (int i = num + 1; i <= m; i++)
	{
		MIN min;
		min=Select(HT,i-1);
		HT[min.s1].parent = i;
		HT[min.s2].parent = i;
		HT[i].lchild = min.s1;
		HT[i].rchild = min.s2;
		HT[i].weight = HT[min.s1].weight + HT[min.s2].weight;
	}
	//输出哈夫曼树存储结构的末态
	for (int i = 1; i <= m; i++)
	{
		cout << "结点序号 " << i << " 权重 " << HT[i].weight << " parent " << HT[i].parent << " lchild " << HT[i].lchild << " rchild " << HT[i].rchild << endl;
	}

}

int main()
{
	cout << "开始创建哈夫曼树" << endl;
	int num;  //结点的个数
	cout << "请输入哈夫曼树叶子结点的个数:";
	cin >> num;
	//创造哈夫曼树
	HuffmanTree HT;
	CreateHuffmanTree(HT, num);
	return 0;
}
  • 7
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
哈夫曼树是一种用于数据压缩的树形结构,可以通过构建哈夫曼树来得到哈夫曼编码。下面是用C++实现哈夫曼树和哈夫曼编码的示例代码: ```c++ #include <iostream> #include <queue> #include <vector> #include <string> #include <unordered_map> using namespace std; // 哈夫曼树节点 struct HuffmanNode { char ch; // 字符 int freq; // 出现频率 HuffmanNode *left, *right; // 左右子节点 HuffmanNode(char c, int f) : ch(c), freq(f), left(nullptr), right(nullptr) {} }; // 用于比较哈夫曼树节点的函数对象 class HuffmanNodeCompare { public: bool operator()(HuffmanNode* a, HuffmanNode* b) { return a->freq > b->freq; // 以出现频率为优先级 } }; // 构建哈夫曼树 HuffmanNode* buildHuffmanTree(string str) { unordered_map<char, int> freqMap; // 统计各字符出现频率 for (char c : str) { freqMap[c]++; } priority_queue<HuffmanNode*, vector<HuffmanNode*>, HuffmanNodeCompare> pq; // 将字符及其出现频率构建成哈夫曼树节点,并加入优先队列 for (auto it = freqMap.begin(); it != freqMap.end(); it++) { HuffmanNode* node = new HuffmanNode(it->first, it->second); pq.push(node); } // 逐步合并哈夫曼树节点,直到只剩下一个节点,即根节点 while (pq.size() > 1) { HuffmanNode* left = pq.top(); pq.pop(); HuffmanNode* right = pq.top(); pq.pop(); HuffmanNode* parent = new HuffmanNode('$', left->freq + right->freq); parent->left = left; parent->right = right; pq.push(parent); } return pq.top(); } // 递归遍历哈夫曼树,得到字符的哈夫曼编码 void getHuffmanCode(HuffmanNode* node, string code, unordered_map<char, string>& codeMap) { if (!node) { return; } if (node->ch != '$') { codeMap[node->ch] = code; } getHuffmanCode(node->left, code + "0", codeMap); getHuffmanCode(node->right, code + "1", codeMap); } int main() { string str = "hello world"; HuffmanNode* root = buildHuffmanTree(str); unordered_map<char, string> codeMap; getHuffmanCode(root, "", codeMap); cout << "Huffman codes:" << endl; for (auto it : codeMap) { cout << it.first << ": " << it.second << endl; } return 0; } ``` 代码中,先统计字符串中各字符的出现频率,然后将它们构建成哈夫曼树节点,并加入优先队列。接着,逐步合并哈夫曼树节点,直到只剩下一个节点,即根节点。最后,递归遍历哈夫曼树,得到各字符的哈夫曼编码。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值