哈夫曼树建立与二叉树WPL算法以及相关例题

目录

哈夫曼树静态数组形式建立

哈夫曼树二叉链表形式建立

求WPL

哈夫曼树编码解码

更新 


哈夫曼树的建立有两种方式,一种是通过静态数组的方式来建立(这种方式比较简洁明了好理解),由于不想篇幅太长了,我还是po出一篇大佬的优秀文章来解释建立哈夫曼树吧

哈夫曼树静态数组形式建立

哈夫曼树的基本概念及创建(c/c++)_gets_s的博客-CSDN博客一、一些基本概念1、路径:从树中一个结点到另一个结点之间的分支构成这两个结点之间的路径。2、路径长度:路径上的分支数目称作路径长度。3、树的路径长度:从树根到每一结点的路径长度之和。4、权:赋予某个实体的一个量,是对实体的某个或某些属性的数值化描述。5、结点的带权路径长度:从该结点到树根之间的路径长度与结点上权的乘积。6、树的带权路径长度:树中所有叶子结点的带权路径长度之和,通常记为:7、哈夫曼树:假设有m个权值{w1,w2,…,wm},可以构造一棵含n个叶子结点的二叉树,每个叶子结点的权为https://blog.csdn.net/gets_s/article/details/106160072?ops_request_misc=&request_id=&biz_id=102&utm_term=%E5%93%88%E5%A4%AB%E6%9B%BC%E6%A0%91%E5%BB%BA%E7%AB%8B&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-1-106160072.nonecase&spm=1018.2226.3001.4187

哈夫曼树二叉链表形式建立

方法:

(1)由原始数据生成森林;

(2) 在森林中选取两棵根结点权值最小的和次小的二叉树作为左右子树构造一棵新的二叉树,其根结点的权值为左右子树根结点权值之和。规定左子树根结点的权值小于右子树根结点的权值。 (3)将新的二叉树加入到森林F中,去除原两棵权值最小的树;

(4)重复2、3步骤,直至F中只剩一棵树为止。 注意:参看书中P146的例子。 

类定义(要用到最小堆)

#include "heap.h"
const  int DefaultSize = 20;	//缺省权值集合大小
template <class T, class E>
struct HuffmanNode {		//树结点的类定义
     E data;				//结点数据
	 HuffmanNode<T, E> *parent;
     HuffmanNode<T, E> *leftChild, *rightChild;	          
                                       //左、右子女和父结点指针
	 HuffmanNode () : Parent(NULL), leftChild(NULL),
          rightChild(NULL) { }	//构造函数	
     HuffmanNode (E elem,                  //构造函数
         HuffmanNode<T, E> *pr = NULL, 
         HuffmanNode<T, E> *left = NULL,		
	     HuffmanNode<T, E> *right = NULL) 
             : data (elem), parent (pr), leftChild (left),  
               rightChild (right) { }	
};

template <class T,  class E>
class HuffmanTree {		//Huffman树类定义
public:
     HuffmanTree (E w[], int n);	//构造函数
     ~HuffmanTree() { delete Tree(root);}  //析构函数
protected:
     HuffmanNode<T, E> *root;	     //树的根
     void deleteTree (HuffmanNode<T, E> *t);			//删除以 t 为根的子树
     void mergeTree (HuffmanNode<T, E>& ht1, HuffmanNode<T, E>& ht2,
     HuffmanNode<T, E> *& parent);
};

实现算法

template <class T, class E>
HuffmanTree<T, E>::HuffmanTree (E w[], int n) {
//给出 n 个权值w[1]~w[n], 构造Huffman树
     minHeap<T, E> hp; 	 //使用最小堆存放森林
     HuffmanNode<T, E> *parent, &first, &second; 
     HuffmanNode<T, E> *NodeList =new HuffmanNode<T,E>[n];    //森林
     for (int i = 0; i < n; i++) {
          	NodeList[i].data = w[i+1];
		NodeList[i].leftChild = NULL;         
          NodeList[i].rightChild = NULL;
          NodeList[i].parent = NULL;
          hp.Insert(NodeList[i]);	//插入最小堆中
     }
     for (i = 0; i < n-1; i++) {	//n-1趟, 建Huffman树
          hp.Remove (first); 		//根权值最小的树
          hp.Remove (second);	//根权值次小的树
		merge (first, second, parent);	//合并
          hp.Insert (*parent);		//重新插入堆中
          root = parent;		//建立根结点
     }
};

template <class T, class E>
void HuffmanTree<T, E>::
mergeTree (HuffmanNode<T, E>& bt1, HuffmanNode<T, E>& bt2, 
    HuffmanNode<T, E> *& parent) {
     parent = new E;
     parent->leftChild = &bt1;
     parent->rightChild = &bt2;
     parent->data.key =bt1.root->data.key+bt2.root->data.key;
     bt1.root->parent = bt2.root->parent = parent; 
}; 

求WPL

 

思路非常棒 

int WPLrec(LBTree* lbt,int n)
{
	int wpl = 0;
	if (lbt != NULL)
	{
		if (lbt->lchild == NULL && lbt->rchild == NULL)
			wpl += n * lbt->weigth;
		wpl += WPLrec(lbt->lchild, n + 1);
		wpl += WPLrec(lbt->rchild, n + 1);
	}
	return wpl;
}

递归算法好理解

下面的例子中深度要初始化为0;

二叉树的带权路径长度WPL算法实现_薛定谔的猫的博客-CSDN博客文章目录题目描述算法思想实现代码题目描述 二叉树的带权路径长度WPL是二叉树中所有叶结点的带权路径长度之和。给定一棵二叉树,采用二叉链表存储,叶子结点的weight域为该结点的权值。请设计一个算法,求二叉树的带权路径长度。算法思想可以使用先序遍历或层次遍历解决问题。<1>算法思想一:基于先序递归遍历。用一个static变量记录WPL,把每个结点的深度作为递归函数的一个参数传递。若该结点是叶结点,则变量WPL加上该结点的深度与权值之和。若该结点是非叶结点,则左子树不为空时,对左子https://blog.csdn.net/weixin_44162361/article/details/120851879?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163506287716780357222924%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=163506287716780357222924&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~hot_rank-5-120851879.first_rank_v2_pc_rank_v29&utm_term=wpl%E7%AE%97%E6%B3%95&spm=1018.2226.3001.4187

哈夫曼树编码解码

编码:

里面的字母的权值代表字母出现的次数; 

方法:

(1)用{ 2,4, 2,3, 3  }作为叶子结点的权值生成一棵哈夫曼树,并将对应权值wi的叶子结点注明对应的字符;

(2)约定左分支表示字符“0”,右分支表示字符‘1’

(3)从叶子结点开始,顺着双亲反推上去,直到根结点,路径上的‘0’或‘1’连接的序列就是结点对应的字符的二进制编码的逆序。

哈夫曼树的建立、编码以及WPL值的计算_SSPUmyl的博客-CSDN博客_哈夫曼树wpl假设用于通信的电文由字符集{A,B,C,D,E,F}中的字母构成,这些字母在电文中出现的概率分别为{0.10,0.19,0.20,0.35,0.12,0.04},要求: 1、构造一棵Huffman树,填写下表,要求左结点的权不大于右结点的权 2、在下表中填入各字符的Huffman编码(左分支为”0”,右分支为”1”) 3、求带权路径长度 解析: 1、哈夫曼树的构造 将电文概率由大到https://blog.csdn.net/SSPUmyl/article/details/53467604?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163505694316780357218848%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=163505694316780357218848&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-2-53467604.first_rank_v2_pc_rank_v29&utm_term=wpl&spm=1018.2226.3001.4187数据结构(15)--哈夫曼树以及哈夫曼编码的实现_小白的专栏-CSDN博客_博夫曼

 


更新 

 太难顶了上面

我这边弄了个初始化Huffman树的简洁代码,没有那么多接口的

初始化

//w[]为每个字符的权重,c[]为每个字符的内容,n为字符的个数,静态实现


struct huffmannode
{
	float weigth;//每个结点的权值
	char s;      //每个结点的数据
	int right, left, parent;
	int code[20];//哈夫曼编码
	int codesize;//每个节点的哈夫曼编码长度
};

huffmanTree::huffmanTree(float w[], char c[], int n) {
    huffmannode *x;
	x = new huffmannode[100];    //长度自定
	int countcode = n;
	int elemsize = countcode * 2 - 1;
	for (int i = 0; i < elemsize; i++)    //初始化
	{
		x[i].s = c[i];
		x[i].weigth = w[i];
		x[i].left = x[i].right = x[i].parent = -1;
	}
	int minfirst, minsecond;
	int postag1, postag2;
	for (int i = 0; i < countcode - 1; i++) {
		minfirst = minsecond = 1000000;    //初始为最大
		postag1 = postag2 = 0;
		for (int j = 0; j < countcode + i; j++)
		{
			if (x[j].weigth < minfirst && x[j].parent == -1)
			{
				minsecond = minfirst;     //最小保存到次小
				postag2 = postag1;
				minfirst = x[j].weigth;
				postag1 = j;
			}
			else if (x[j].weigth < minsecond && x[j].parent == -1)
			{
				minsecond = x[j].weigth;
				postag2 = j;
			}
		}
		x[postag1].parent = countcode + i;
		x[postag2].parent = countcode + i;
		x[countcode + i].weigth = x[postag1].weigth + x[postag2].weigth;
		x[countcode + i].left = postag1;
		x[countcode + i].right = postag2;
		x[countcode + i].parent = -1;
	}
}

 编码

//countcode为字符个数,x为Huffman树,利用栈来实现编码解码
void huffmanTree::encode(int countcode,huffmanTree *x) {
	stack<int> s;
	int j, count;
	for (int i = 0; i < countcode; i++)
	{
		j = i;
		while (x[j].parent != -1)
		{
			if (x[x[j].parent].left== j) { s.push(0); }
			else if (x[x[j].parent].right == j) { s.push(1); }
			j = x[j].parent;
		}
		int temp = 0;
		while (!s.empty())
		{
			x[i].code[temp++] = s.top();
			s.pop();
		}
		x[i].codesize = temp;
	}
	cout << "编码成功!" << endl;
}

解码

//elemsize是静态数组哈夫曼树中开辟的空间,即:空间大小=节点个数*2-1
void huffmanTree::decode(int elemsize) {
	int w = elemsize - 1;
	char co;
	while (cin>>co) {
		co=in.get();        //读co的‘0’,‘1’字符
		if (co == '0') {
			w = x[w].left;
		}
		else if (co == '1') {
			w = x[w].right;
		}

		if (x[w].left == -1 && x[w].right == -1) {
			cout << x[w].s;
			w = elemsize - 1;
		}
	}
	cout << "译码成功!" << endl;
}

 

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
哈夫曼树的带权路径长度(WPL)是指所有叶子节点的带权路径长度之和。构造哈夫曼树算法如下: 1. 首先,根据给定的字符集和它们在电文中出现的概率,将每个字符看作一个节点,并将节点的权值设置为对应概率。 2. 将这些节点按照权值从小到大排序,并将它们依次放入一个优先队列(或最小堆)中。 3. 从优先队列中选择权值最小的两个节点,将它们作为左右子节点创建一个新的节点,新节点的权值为两个子节点的权值之和。 4. 将新节点插入优先队列中,重复步骤3,直到优先队列中只剩下一个节点,即哈夫曼树的根节点。 5. 根据哈夫曼树的构造过程,可以得到每个字符的Huffman编码。从根节点出发,向左走表示编码为0,向右走表示编码为1,直到叶子节点。 6. 将每个字符的Huffman编码填入对应的表格中。 7. 最后,计算带权路径长度,即将每个叶子节点的权值乘以对应的编码长度,并将它们相加即可得到WPL值。 以上就是构造哈夫曼树计算WPL算法。 [3<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [哈夫曼树及求其WPL算法](https://blog.csdn.net/Wizzy_Ang/article/details/125548685)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [哈夫曼树建立二叉树WPL算法以及相关例题](https://blog.csdn.net/weixin_51578598/article/details/120935284)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值