哈夫曼树与哈夫曼编码、集合

什么是哈夫曼树(Huffman Tree)
eg:将百分制的考试成绩转换为五分制的成绩
if ( score < 60 ) grade = 1;
else if ( score < 70 ) grade = 2;
else if ( score < 80 ) grade = 3;
else if ( score < 90 ) grade = 4;
else grade = 5;
建立判定树,如果考虑到学生成绩的分布概率,我们发现得3分和得4分的同学占了绝大多数的比例,直接用上述判别流程建立判定树 显然效率不够高。
修改判定树:
if ( score < 80 )
{
if ( score < 70 )
if ( score < 60 ) grade = 1 ;
else grade = 2 ;
} else if ( score < 90 ) grade = 4 ;
else grade = 5;
按照这种判别流程建立的判定树 效率得到显著提高。
如何根据结点不同的查找频率 构造更有效的搜索树?

-哈夫曼树的定义

带权路径长度(WPL):设二叉树有n个叶子结点,每个叶子结点带有权值(即频率)Wk,从根结点到每个叶子结点的长度为Lk,则每个叶子结点的带权路径长度之和为 WPL=W1L1+W2L2+ …… +Wn*Ln
目标:将WPL降到最低。最优二叉树或哈夫曼树就是WPL最小的二叉树

-哈夫曼树的构造:

每次把权值最小的两棵二叉树合并,得到的新结点的权值为两棵树的权值的和,再由新结点与剩下的结点中再挑出两个权值最小的树 再次合并,直到最后所有树连接在一起
如何选取两个最小的树?利用堆
typedef struct TreeNode *HuffmanTree ;
struct TreeNode {
int Weight ;
HuffmanTree Left, Right ;
}
HuffmanTree Huffman ( MinHeap H )
{
// 假设 H -> Size 个权值已经存在 H -> Element [ ]-> Weight 里
int i ; HuffmanTree T ;
BuildMinHeap ( H ) ; // 将 H -> Element [ ]按权值调整为最小堆
for ( i = 1 ; i < H -> Size ; i ++ ) { // 做 H -> Size - 1 次合并
T = malloc ( sizeof ( struct TreeNode ) ) ; // 建立新结点
// 从最小堆中删除一个结点 作为新树的左子结点
T -> Left = DeleteMin ( H ) ;
// 从最小堆中删除一个结点 作为新树的右子结点
T -> Right = DeleteMin ( H ) ;
// 计算新权值
T -> Weight = T -> Left -> Weight + T -> Right -> Weight ;
Insert ( H , T ) ; // 将新树插入最小堆
}
T = DeleteMin ( H ) ;
return T ;
}
整体复杂度为 O( N logN )

-哈夫曼树的特点:

没有度为1的结点
n个叶结点的哈夫曼树共有2n-1个结点: n0:叶结点总数,n1:只有一个儿子的结点总数,n2:有两个儿子的结点总数; 可知:n2=n0-1;
哈夫曼树的任意非叶结点的左右子树交换后仍是哈夫曼树;
对同一组权值,存在不同构的两棵哈夫曼树,不过WPL值是一样的

-哈夫曼编码

给定一段字符串,如何对字符串进行编码,可以使得该字符串的编码存储空间最少?
假设有一段文本 包含58个字符,并且由以下7个字符构成:a,e,i,s,t,空格(sp),换行(nl);这7个字符出现的次数不同。如何对这7个字符进行编码 使得总编码空间最少?
分析:
(1)用等长ASCII编码:58 x 8=464位;
(2)用等长3位编码:58 x 3=174位;(因为只有7个字符,3位编码可编8个字符)
(3)不等长编码:出现频率高的字符用的编码短些,出现频率低的字符则可以编码长些
不等长编码会长生二义性,如a=1,e=0,s=11,t=10;那么编码1011就会有多种不同意思,因为我们不知道各个编码长度具体是多少。
前缀码(prefix code):任何字符的编码都不是另一字符编码的前缀,可以无二义地解码
用二叉树进行编码:(1)左右分支:0、1 (2)字符只在叶结点上
只要待编字符在叶结点上,其二叉树编码都不是另一字符编码的前缀
由哈夫曼树构造一棵编码代价最小的树
例:

002WV0d1zy70O2MDV1H55&690.png

-集合的表示:

集合运算:交集、并集、补集、差集,判定一个元素是否属于某一集合
并查集:集合并、查某元素属于什么集合
eg:10台电脑{1,2,3,…,9,10}已知下列电脑之间已经实现了连接:1和2、2和4、3和5、4和7、5和8、6和9、6和10,问2和7之间、5和9之间是否是连通的
思路:(1)将10台电脑看成10个集合(2)已知一种连接“x和y”,就将x和y对应的集合合并(3)查询“x和y是否是连通的”就是判别x和y是否属于同一集合;这种思路就是并查集。
并查集问题中集合存储的实现:
可以用树结构表示集合,树的每一个结点代表一个集合元素;双亲表示法:孩子指向双亲
采用数组存储形式:data表示元素的值,Parent表示其父结点的下标,根结点的Parent用-1表示;
数组中每个元素的类型描述为:
typedef struct {
ElementType Data ;
int Parent ; // 每个结点的父结点的下标
} SetType ;

-集合运算

(1)查找某个元素所在的集合(用根结点表示)

int Find ( SetType S [ ], ElementType X )
{ // 在数组 S 中查找值为 X 的元素所属的集合
// MaxSize 是全局变量,为数组 S 的最大长度
int i ;
for ( i = 0 ; i < MaxSize && S [ i ]. Data != X ; i ++ ) ;
if ( i >= MaxSize ) return -1 ; // 未找到X,返回-1
for ( ; S [ i ] . Parent >= 0 ; i = S [ i ] . Parent ) ;
return i ; // 找到X所属集合,返回树根结点在数组S中的下标
}

(2)集合的并运算

分别找到X1和X2两个元素所在集合树的根结点,如果它们不同根 则将其中一个根结点的父结点指针设置成另一个根结点的数组下标。
void Union ( SetType S[ ], ElementType X1 , ElementType X2 )
{
int Root1 , Root2 ;
Root1 = Find ( S , X1 ) ;
Root2 = Find ( S , X2 ) ;
if ( Root != Root2 ) S[ Root2 ] . Parent = Root1 ;
}

这样并集后,树越来越大越来越高,树高了之后Find函数效率会变差,所以尽量把小的集合并到大的集合中去;用负数代表根结点,负数的绝对值为这棵树的元素个数

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容

  • B树的定义 一棵m阶的B树满足下列条件: 树中每个结点至多有m个孩子。 除根结点和叶子结点外,其它每个结点至少有m...
    文档随手记阅读 13,097评论 0 25
  • 课程介绍 先修课:概率统计,程序设计实习,集合论与图论 后续课:算法分析与设计,编译原理,操作系统,数据库概论,人...
    ShellyWhen阅读 2,222评论 0 3
  • 这篇文章收录在我的 Github 上 algorithms-tutorial,另外记录了些算法题解,感兴趣的可以看...
    Lindz阅读 8,732评论 1 6
  • 好久没有更文了。 坚持真的不是说一说罢了。 上个月活动也蛮多的 每天的更文其实更能让自己认清自己, 内心也不是那么...
    SU呐阅读 144评论 0 0
  • 吃过早饭,趁天凉快,带着大宝和二宝去了趟超市。大宝说想喝纯奶了,酸奶又喝够了。行啊,那就买一箱,毕竟喝奶...
    邓启旭邓君浩妈妈阅读 129评论 0 1