当前位置:网站首页>哈夫曼樹(一)基本概念與C語言實現
哈夫曼樹(一)基本概念與C語言實現
2022-06-30 20:31:00 【生活需要深度】
本章介紹哈夫曼樹。和以往一樣,本文會先對哈夫曼樹的理論知識進行簡單介紹,然後給出C語言的實現。後續再分別給出C++和Java版本的實現;實現的語言雖不同,但是原理如出一轍,選擇其中之一進行了解即可。若文章有錯誤或不足的地方,請幫忙指出!
目錄
1. 哈夫曼樹的介紹
2. 哈夫曼樹的圖文解析
3. 哈夫曼樹的基本操作
4. 哈夫曼樹的完整源碼轉載請注明出處:如果天空不死 - 博客園
更多內容:數據結構與算法系列 目錄
哈夫曼樹的介紹
Huffman Tree,中文名是哈夫曼樹或霍夫曼樹,它是最優二叉樹。起源主要是信息編碼傳輸,主要應用於信息編碼和數字壓縮領域,目前也是現代壓縮算法的基礎。
定義:給定n個權值作為n個葉子結點,構造一棵二叉樹,若樹的帶權路徑長度達到最小,則這棵樹被稱為哈夫曼樹。 這個定義裏面涉及到了幾個陌生的概念,下面就是一顆哈夫曼樹,我們來看圖解答。

(01) 路徑和路徑長度
定義:在一棵樹中,從一個結點往下可以達到的孩子或孫子結點之間的通路,稱為路徑。通路中分支的數目稱為路徑長度。若規定根結點的層數為1,則從根結點到第L層結點的路徑長度為L-1。
例子:100和80的路徑長度是1,50和30的路徑長度是2,20和10的路徑長度是3。
(02) 結點的權及帶權路徑長度
定義:若將樹中結點賦給一個有著某種含義的數值,則這個數值稱為該結點的權。結點的帶權路徑長度為:從根結點到該結點之間的路徑長度與該結點的權的乘積。
例子:節點20的路徑長度是3,它的帶權路徑長度= 路徑長度 * 權 = 3 * 20 = 60。
(03) 樹的帶權路徑長度
定義:樹的帶權路徑長度規定為所有葉子結點的帶權路徑長度之和,記為WPL。
例子:示例中,樹的WPL= 1*100 + 2*80 + 3*20 + 3*10 = 100 + 160 + 60 + 30 = 350。
比較下面兩棵樹

上面的兩棵樹都是以{10, 20, 50, 100}為葉子節點的樹。
左邊的樹WPL=2*10 + 2*20 + 2*50 + 2*100 = 360
右邊的樹WPL=350
左邊的樹WPL > 右邊的樹的WPL。你也可以計算除上面兩種示例之外的情况,但實際上右邊的樹就是{10,20,50,100}對應的哈夫曼樹。至此,應該堆哈夫曼樹的概念有了一定的了解了,下面看看如何去構造一棵哈夫曼樹。
哈夫曼樹的圖文解析
假設有n個權值,則構造出的哈夫曼樹有n個葉子結點。 n個權值分別設為 w1、w2、…、wn,哈夫曼樹的構造規則為:
1. 將w1、w2、…,wn看成是有n 棵樹的森林(每棵樹僅有一個結點);
2. 在森林中選出根結點的權值最小的兩棵樹進行合並,作為一棵新樹的左、右子樹,且新樹的根結點權值為其左、右子樹根結點權值之和;
3. 從森林中删除選取的兩棵樹,並將新樹加入森林;
4. 重複(02)、(03)步,直到森林中只剩一棵樹為止,該樹即為所求得的哈夫曼樹。
以{5,6,7,8,15}為例,來構造一棵哈夫曼樹。

第1步:創建森林,森林包括5棵樹,這5棵樹的權值分別是5,6,7,8,15。
第2步:在森林中,選擇根節點權值最小的兩棵樹(5和6)來進行合並,將它們作為一顆新樹的左右孩子(誰左誰右無關緊要,這裏,我們選擇較小的作為左孩子),並且新樹的權值是左右孩子的權值之和。即,新樹的權值是11。 然後,將"樹5"和"樹6"從森林中删除,並將新的樹(樹11)添加到森林中。
第3步:在森林中,選擇根節點權值最小的兩棵樹(7和8)來進行合並。得到的新樹的權值是15。 然後,將"樹7"和"樹8"從森林中删除,並將新的樹(樹15)添加到森林中。
第4步:在森林中,選擇根節點權值最小的兩棵樹(11和15)來進行合並。得到的新樹的權值是26。 然後,將"樹11"和"樹15"從森林中删除,並將新的樹(樹26)添加到森林中。
第5步:在森林中,選擇根節點權值最小的兩棵樹(15和26)來進行合並。得到的新樹的權值是41。 然後,將"樹15"和"樹26"從森林中删除,並將新的樹(樹41)添加到森林中。
此時,森林中只有一棵樹(樹41)。這棵樹就是我們需要的哈夫曼樹!
哈夫曼樹的基本操作
哈夫曼樹的重點是如何構造哈夫曼樹。本文構造哈夫曼時,用到了以前介紹過的"(二叉堆)最小堆"。下面對哈夫曼樹進行講解。
1. 基本定義

typedef int Type;
typedef struct _HuffmanNode {
Type key; // 權值
struct _HuffmanNode *left; // 左孩子
struct _HuffmanNode *right; // 右孩子
struct _HuffmanNode *parent; // 父節點
} HuffmanNode, *HuffmanTree;

HuffmanNode是哈夫曼樹的節點類。
2. 構造哈夫曼樹

/*
* 創建Huffman樹
*
* 參數說明:
* a 權值數組
* size 數組大小
*
* 返回值:
* Huffman樹的根
*/
HuffmanNode* create_huffman(Type a[], int size)
{
int i;
HuffmanNode *left, *right, *parent;
// 建立數組a對應的最小堆
create_minheap(a, size);
for(i=0; i<size-1; i++)
{
left = dump_from_minheap(); // 最小節點是左孩子
right = dump_from_minheap(); // 其次才是右孩子
// 新建parent節點,左右孩子分別是left/right;
// parent的大小是左右孩子之和
parent = huffman_create_node(left->key+right->key, left, right, NULL);
left->parent = parent;
right->parent = parent;
// 將parent節點數據拷貝到"最小堆"中
if (dump_to_minheap(parent)!=0)
{
printf("插入失敗!\n結束程序\n");
destroy_huffman(parent);
parent = NULL;
break;
}
}
// 銷毀最小堆
destroy_minheap();
return parent;
}

首先通過create_huffman(a, size)來一個最小堆。最小堆構造完成之後,進入for循環。
每次循環時:
(01) 首先,將最小堆中的最小節點拷貝一份並賦值給left,然後重塑最小堆(將最小節點和後面的節點交換比特置,接著將"交換比特置後的最小節點"之前的全部元素重新構造成最小堆);
(02) 接著,再將最小堆中的最小節點拷貝一份並將其賦值right,然後再次重塑最小堆;
(03) 然後,新建節點parent,並將它作為left和right的父節點;
(04) 接著,將parent的數據複制給最小堆中的指定節點。
在二叉堆中已經介紹過堆,這裏就不再對堆的代碼進行說明了。若有疑問,直接參考後文的源碼。其它的相關代碼,也Please RTFSC(Read The Fucking Source Code)!
哈夫曼樹的完整源碼
哈夫曼樹的源碼共包括4個文件。
边栏推荐
- 居家办公没有“血泪史”| 社区征文
- unittest自动测试多个用例时,logging模块重复打印解决
- The Commission is so high that everyone can participate in the new programmer's partner plan
- 【ICLR 2021】半监督目标检测:Unbiased Teacher For Semi-Supervised Object Detection
- 数据库 OLAP、OLTP是什么?相同和不同?适用场景
- exness:流动性系列-流动性清洗和反转、决策区间
- MySQL master-slave synchronization
- 大神详解开源 BUFF 增益攻略丨直播
- Jerry's determination of detection sensitivity level [chapter]
- exness:美GDP终值意外加速萎缩1.6%
猜你喜欢

How unity pulls one of multiple components

The Commission is so high that everyone can participate in the new programmer's partner plan

maya房子建模
![Jerry's touch key recognition process [chapter]](/img/3e/bb73c735d0a7c7a26989c65a432dad.png)
Jerry's touch key recognition process [chapter]

obsidian配合hugo的使用,让markdown本地编辑软件与在线化无缝衔接

Golang应用 ━━ 安装、配置与使用hugo博客系统

Lambda expression principle analysis and learning (June 23, 2022)

屏幕显示技术进化史

maya房子建模

杰理之触摸按键识别流程【篇】
随机推荐
微信小程序开发实战 云音乐
基于slate构建文档编辑器
操作系统面试题汇总(不定期更新)
数据库 OLAP、OLTP是什么?相同和不同?适用场景
Jerry's touch key recognition process [chapter]
Qt:qaxobject operation Excel
Jerry's determination of detection sensitivity level [chapter]
北京大学ACM Problems 1003:Hangover
断点续传和下载原理分析
【ICLR 2021】半监督目标检测:Unbiased Teacher For Semi-Supervised Object Detection
Why must we move from Devops to bizdevops?
漏洞扫描工具大全,妈妈再也不用担心我挖不到漏洞了
Summary of operating system interview questions (updated from time to time)
文件包含&条件竞争
消灭Bug,开发者不可不知的几款Bug探索测试神器。
Summary of PHP file upload (garbled code, move failure, permission, display picture)
exness:流动性系列-流动性清洗和反转、决策区间
静态类使用@Resource注解注入
GeoServer installation
CADD course learning (2) -- target crystal structure information