基础入门之哈夫曼树

学习材料:《2013年王道论坛计算机考研机试指南》

文中涉及对学习材料的摘录,以及自己的理解


1 基本概念

路径:1棵树中,从一个结点到另一个结点的通路

路径长度:该路径上所需经过的边的个数

带权路径长度:假设树中结点有权值,那么从根节点到达该节点的路径长度再乘以该结点权值,就是该结点的带权路径长度

树的带权路径长度和:1棵树所有叶子结点的带全路径长度和

哈夫曼树:对于给定的N个结点(有固定权值),以它们为叶子结点构造的二叉树,其中带权路径和最小的一棵二叉树,就是哈夫曼树,同时也被称为最优树。

对于给定N个结点(叶子结点)的哈夫曼树不唯一。


2 哈夫曼树求法

1) 将所有结点放入集合K;

2) 若K中剩余结点>2个, 从K中取出权值最小的2个结点, 创建一个新结点, 使取出的两个结点为该新结点的左右儿子, 设定它的权值为这两个儿子结点的权值和, 并将该新结点放入集合K.

3) 重复2), 直到K中只有1个结点, 它就是所构造的哈弗曼树的根节点; 同时, 过程中所有创建的中间结点(非叶子节点)的权值和, 就是该哈弗曼树的带权路径和.

如下二叉树, 各节点就用其权值的数值表示:

                    6

                 /       \

              3           3

           /      \

        1          2

给定叶子结点为: 1,2,3

构造过程:   K集合: 1,2,3 ;    取1,2, 新结点权值3, K集合: 3,3;        取3,3,新结点权值6, K集合:  6

带权路径和: 3 + 6 = 9         从叶子结点到根节点带权路径的求法: 1*(1+1) + 2*(1+1) + 3*1 = 9


3 求解哈夫曼树过程可利用的数据结构——优先队列

普通队列:先进先出; 优先队列:优先级高的先出

求解哈夫曼树问题:要获得集合中权值最小的结点,使用堆栈数据结构,即每次要弹出n个元素中最小的元素,因此可直接用优先队列来实现。

新建一个这样的堆:

priority_queue<int> Q; //大顶堆,即这样建立的堆,从中取元素,默认取整个堆中最大的元素。
priority_queue<int, vector<int>, greater<int>> Q;   //小顶堆,默认先取得该堆中最小的元素


堆有关操作:

Q.push(x);         //将int型元素x放入堆Q中

int a = Q.top();  //取出堆顶元素,即最小元素,保存在a中

Q.pop();            //弹出堆顶元素,取出后堆会自动调整为1个新的小顶堆

/*在运用标准模板库queue时,必须包含如下语句:*/
#include <queue>
using namespace std;


4 题目

/*
* 知识点:哈弗曼树 
* 题目:给定n个叶节点及其权值, 求所构造得到的哈弗曼树的带权路径和
* 输入: 2行,  第一行输入一个数n(2<= n <= ),表示叶节点个数;  第二行输入这n个叶节点的权值
* 输出: 哈弗曼树的带权路径和
* 测试用例:
  input: 
  5
  1 2 2 5 9
  output:
  37    (1+2=3 2+3=5 5+5=10 9+10=19   3+5+10+19=37)
* 程序思路:利用优先队列创建小顶堆,把叶节点权值放入小顶堆,依次取出2个最小的权值,相加后存入小顶堆,最后把中间过程两两相加和再求和
*/

#include 
#include 
#include    
using namespace std;

priority_queue, greater> Q;   //创建小顶堆, 头文件必须包含才能使用greater标识符 否则默认的只能使用less(那样是大顶堆) 

int main()
{
	int n;
	int i;
	int huff_sum;
	while( scanf("%d",&n) != EOF )
	{
		while( Q.empty()==false )                   //初始化 清空堆中元素 因为要输入多组数据
			Q.pop();
		for(i=1; i<=n; i++)
		{
			int x;
			scanf("%d",&x);                         //scanf会忽略空格,scanf把空格,回车等默认为一个数的结束 所以再输入第二行权值时 可以采用 1 2 2 5 9空格隔开的方式
			Q.push(x);
		}
        
		huff_sum = 0;
		while( Q.size() >=2 )
		{
			int a = Q.top();
			Q.pop();
			int b = Q.top();
			Q.pop();
			huff_sum += a+b;
			Q.push(a+b);
		}

		printf("%d\n", huff_sum);
	}
	return 0;
}

5 哈夫曼树的应用

哈夫曼树编码、多个数的两两合并



                   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值