數據結構 —— 哈夫曼樹

數據結構 —— 哈夫曼樹

  • 哈夫曼樹
      • 定義
      • 構造算法
      • 特性
      • 應用
  • 哈夫曼編碼
      • 核心概念
      • 工作原理
      • 特點

我們今天來看哈夫曼樹

哈夫曼樹

哈夫曼樹(Huffman Tree),是一種特殊的二叉樹,由D.A. Huffman在1952年提出,主要用于數據壓縮,特別是哈夫曼編碼(Huffman Coding)中。以下是關于哈夫曼樹的全面概念:

定義

哈夫曼樹是一種帶權路徑長度最短的二叉樹,也稱為最優二叉樹。它是在給定一組具有不同權重的葉子節點(通常代表數據中的符號或字符)的情況下,通過特定的構建算法得到的。該樹的特點是,所有葉子節點位于最底層或倒數第二層,且沒有度為1的節點(除了根節點可能外),同時保證了從根節點到任何葉子節點的路徑上的權值之和(即帶權路徑長度)最小。

舉個例子:
在這里插入圖片描述
在這里插入圖片描述

構造算法

  1. 初始化:將每個權重作為一個葉子節點,放入一個優先隊列(優先級基于節點權重,通常使用最小堆實現)。
  2. 合并節點:從隊列中取出兩個權重最小的節點,創建一個新的內部節點,其權重為這兩個節點的權重之和,新節點作為這兩個節點的父節點。
  3. 重復步驟2:將新創建的節點放回優先隊列,重復上述過程,直到隊列中只剩下一個節點,該節點即為哈夫曼樹的根節點。
  4. 生成編碼:從根到每個葉子節點的路徑可以轉化為一個唯一的二進制字符串(路徑上向左走記為0,向右走記為1),這個字符串就是該葉子節點代表的字符的哈夫曼編碼。

在這里插入圖片描述這里我沒有寫得那么復雜,我用一個vector維護森林,并且排好序,然后依次拿出構造哈夫曼樹:

#pragma once
#include<algorithm>
#include<iostream>
#include<vector>// 定義霍夫曼樹節點結構體
template<class T>
struct HuffManTreeNode
{
public:// 構造函數,初始化節點數據、左孩子和右孩子HuffManTreeNode(T data):_data(data), _leftchild(nullptr), _rightchild(nullptr){}// 拷貝構造函數,用于復制已有節點的信息HuffManTreeNode(HuffManTreeNode<T>* node):_data(node->_data), _leftchild(node->_leftchild), _rightchild(node->_rightchild){}// 析構函數~HuffManTreeNode(){}// 創建新節點并返回指針HuffManTreeNode<T>* CreateNode(T data){HuffManTreeNode<T>* newnode = new HuffManTreeNode(data);return newnode;}// 根據已有節點創建新節點并返回指針HuffManTreeNode<T>* CreateNode(HuffManTreeNode<T>* node){HuffManTreeNode<T>* newnode = new HuffManTreeNode(node);return newnode;}// 向樹中插入新節點void Insert(HuffManTreeNode<T>*& node, T data){HuffManTreeNode<T>* newnode = CreateNode(data);if (newnode == nullptr){perror("new fail");return;}if (node->_leftchild == nullptr){node->_leftchild = newnode;}else if (node->_rightchild == nullptr){node->_rightchild = newnode;}return;}// 向樹中插入已有節點void Insert(HuffManTreeNode<T>*& node, HuffManTreeNode<T>* temp){if (node->_leftchild == nullptr){node->_leftchild = CreateNode(temp);}else if (node->_rightchild == nullptr){node->_rightchild = CreateNode(temp);}return;}// 重載賦值運算符HuffManTreeNode<T>& operator=(const HuffManTreeNode<T>* node){if (this == node){return *this;}_data = node->_data;_leftchild = node->_leftchild;_rightchild = node->_rightchild;return *this;}// 數據成員T _data;// 左右孩子指針HuffManTreeNode<T>* _leftchild;HuffManTreeNode<T>* _rightchild;
};// 中序遍歷霍夫曼樹
template<class T>
void Inorder(HuffManTreeNode<T>* node)
{if (node == nullptr){return;}Inorder(node->_leftchild); // 遍歷左子樹std::cout<< node->_data << " "; // 訪問當前節點Inorder(node->_rightchild); // 遍歷右子樹
}
#include"Huffman.h"int main()
{std::vector<int> vt = {1,45,12,56,78,0,1,3};std::sort(vt.begin(),vt.end());for(auto e : vt){std::cout << e << " ";}std::cout<<std::endl;//創建哈夫曼樹HuffManTreeNode<int>* node = new HuffManTreeNode(vt[0]+vt[1]);node->Insert(node,vt[0]);node->Insert(node,vt[1]);for(int i = 2 ; i < vt.size(); i++){HuffManTreeNode<int>* temp = node;node = node->CreateNode(node->_data +vt[i]);node->Insert(node,temp);node->Insert(node,vt[i]);}Inorder(node);return 0;
}

在這里插入圖片描述

特性

  • 最優性:在所有葉子節點數量相同且節點權值已知的二叉樹中,哈夫曼樹的帶權路徑長度是最小的。
  • 編碼效率:哈夫曼編碼根據字符出現的頻率分配編碼,高頻字符的編碼較短,低頻字符的編碼較長,從而在整體上達到高效的數據壓縮效果。
  • 無損編碼:哈夫曼編碼是一種無損數據壓縮方法,可以完全恢復原始數據。
  • 自適應性:雖然經典哈夫曼編碼基于靜態概率模型,但存在變體如自適應哈夫曼編碼,能夠根據數據流動態調整編碼表,適用于數據統計特性隨時間變化的情況。

應用

  • 數據壓縮:廣泛應用于文本、圖像、音頻等數據的無損壓縮。
  • 通信系統:優化數據傳輸,減少帶寬需求。
  • 文件存儲:減小文件大小,節約存儲空間。
  • 編譯器:用于詞法分析中的關鍵字識別,通過為常用關鍵字分配較短編碼,提高解析速度。

哈夫曼編碼

哈夫曼編碼(Huffman Coding)是一種高效的熵編碼(Entropy Encoding)方法,用于無損數據壓縮。它是基于哈夫曼樹(Huffman Tree)構造的一種數據編碼方式,由David A. Huffman在1952年提出。以下是哈夫曼編碼的核心概念、工作原理以及特點:

核心概念

哈夫曼編碼的基本思想是根據數據中各個符號(如字符、像素值等)出現的頻率來為它們分配不同的編碼,出現頻率高的符號分配較短的編碼,而頻率低的符號則分配較長的編碼。這樣,當整個數據集被編碼時,由于高頻符號使用的短編碼能頻繁重復,從而實現整體數據量的壓縮。

工作原理

  1. 頻率統計:首先統計待編碼數據中每個符號出現的頻率。
  2. 構建哈夫曼樹:使用頻率作為權重,通過哈夫曼樹的構造算法(見前述哈夫曼樹的構造過程),構建一棵二叉樹。在這個過程中,每次都將兩個最小頻率的節點合并成一個新的節點,新節點的頻率是兩個子節點頻率之和。
  3. 生成編碼:從哈夫曼樹的根到每個葉子節點的路徑定義了該葉子節點代表符號的編碼。具體來說,向左分支時編碼添加一個“0”,向右分支時添加一個“1”。因此,葉子節點越深,其對應的編碼就越長。
  4. 編碼數據:使用生成的哈夫曼編碼表對原始數據進行編碼,即將數據中的每個符號替換為其對應的編碼字符串。

特點

  • 無損編碼:哈夫曼編碼是一種無損數據壓縮技術,意味著解碼后可以完全恢復原始數據。
  • 自適應性:雖然標準哈夫曼編碼需要預先知道數據的概率分布,但可以通過動態哈夫曼編碼技術,在不知道全部數據的情況下逐步更新編碼表,適應數據流的變化。
  • 效率:在所有前綴編碼(即任意編碼都不會是另一個編碼的前綴)中,哈夫曼編碼提供了理論上的最優平均編碼長度,即熵的上限。
  • 簡單性:盡管編碼效率高,哈夫曼編碼的算法實現相對直接且易于理解。

在這里插入圖片描述在這里插入圖片描述
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/36434.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/36434.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/36434.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[面試題]計算機網絡

[面試題]Java【基礎】[面試題]Java【虛擬機】[面試題]Java【并發】[面試題]Java【集合】[面試題]MySQL[面試題]Maven[面試題]Spring Boot[面試題]Spring Cloud[面試題]Spring MVC[面試題]Spring[面試題]MyBatis[面試題]Nginx[面試題]緩存[面試題]Redis[面試題]消息隊列[面試題]…

ES報錯:解決too_many_clauses: maxClauseCount is set to 1024 報錯問題

解決too_many_clauses: maxClauseCount is set to 1024 報錯問題 問題場景報錯信息問題分析解決1. 優化查詢2. 增加maxClauseCount3. 改用其他查詢類型修改后的查詢示例 問題場景 查詢語句&#xff1a;查詢clcNo分類號包含分類O的所有文檔 {"match_phrase_prefix":…

社會與網絡的討論#1

“拒絕心靈雞湯” 都說人人平等&#xff0c;那請問一個有錢人看到一個掃大街的&#xff0c;能有幾個保證不產生厭惡感的&#xff1f; 你能確保&#xff0c;你的工資會比有關系的人的工資高嗎&#xff1f; 你進入公司&#xff0c;有有關系的人進入的方便嗎&#xff1f; 在學…

特產零售元宇宙:探索虛擬世界的商業機遇

在數字化時代&#xff0c;元宇宙作為一個全新的虛擬世界&#xff0c;正在逐漸改變我們的生活方式和商業模式。隨著技術的不斷發展&#xff0c;特產零售業也開始嘗試進入這個充滿無限可能的新領域。本文將探討特產零售元宇宙的概念、優勢以及面臨的挑戰&#xff0c;并分析其未來…

WAIC2024 | 華院計算邀您共赴2024年世界人工智能大會,見證未來科技革新

在智能時代的浪潮洶涌澎湃之際&#xff0c;算法已成為推動社會進步的核心力量。作為中國認知智能技術的領軍企業&#xff0c;華院計算在人工智能的廣闊天地中&#xff0c;不斷探索、創新&#xff0c;致力于將算法的潛力發揮到極致。在過去的時日里&#xff0c;華院計算不斷探索…

Java - Execl自定義導入、導出

1.需求&#xff1a;問卷星答 下圖框出區域&#xff0c;為用戶自定義字段問題及答案 2.采用技術EasyExcel 模板所在位置如下 /*** 導出模板** param response*/ Override public void exportTemplate(HttpServletResponse response) throws IOException {ClassPathResource c…

Metricbeat和Prometheus監控比較

Metricbeat和Prometheus是兩種常見的監控工具&#xff0c;它們都有收集和存儲系統和應用程序性能數據的功能&#xff0c;但它們的設計理念、實現方式和適用場景有所不同。以下是它們的相同點和不同點的詳細比較&#xff1a; 相同之處 數據收集&#xff1a; Metricbeat 和 Pro…

vue 使用 face-api.js 實現人臉識別

HTML 代碼如下 <div class="videoBox" id="videoBox"><video ref="videoPlayer" width="800" height="600" autoplay muted playsinline></video><canvas ref="overlay"></canvas>…

配置 Cmder 到鼠標右鍵

win Q 快捷鍵搜索 cmd&#xff0c;以管理員身份運行 在命令行輸入 cmder.exe /REGISTER ALL

OpenCloudOS開源的操作系統

OpenCloudOS 是一款開源的操作系統&#xff0c;致力于提供高性能、穩定和安全的操作系統環境&#xff0c;以滿足現代計算和應用程序的需求。它結合了現代操作系統設計的最新技術和實踐&#xff0c;為開發者和企業提供了一個強大的平臺。本文將詳細介紹 OpenCloudOS 的背景、特性…

品牌進行3D數字化轉型,有哪些優勢?

各行業都在經歷著從增量市場向存量市場的轉變&#xff0c;同時用戶的消費觀念也日趨成熟&#xff0c;更加注重產品的體驗和服務質量。 無論是線上購物平臺還是線下實體門店&#xff0c;提供個性化和增強體驗感的產品與服務已成為未來發展的核心驅動力&#xff0c;品牌轉型也迫…

SyncFolders文件備份—辦公人員必備

SyncFolders支持在兩個或多個文件夾之間同步文件&#xff0c;用戶可以將重要文件同步到多個位置&#xff0c;如備份硬盤、網絡共享文件夾或云存儲等。通過設定同步規則&#xff0c;可以自動備份和同步更新&#xff0c;減少手動操作的繁瑣&#xff0c;確保文件的安全和可訪問性。…

uniapp橫屏移動端卡片縮進輪播圖

uniapp橫屏移動端卡片縮進輪播圖 效果&#xff1a; 代碼&#xff1a; <!-- 簡單封裝輪播圖組件:swiperCard --> <template><swiper class"swiper" circular :indicator-dots"true" :autoplay"true" :interval"10000&quo…

標準庫STL

標準庫STL stringstreamvector自定義類型初始化為一個數 queue stringstream 頭文件sstream。格式化字符流 #include <iostream> #include <sstream> using namespace std; int main(){stringstream ss;// hex 以十六進制保存 oct是8進制ss <<89<<…

軟件必須要進行跨瀏覽器測試嗎?包括哪些內容和注意事項?

隨著互聯網的普及和發展&#xff0c;用戶對軟件的要求越來越高。無論是在臺式機、筆記本還是移動設備上&#xff0c;用戶都希望能夠以最好的體驗來使用軟件。然而&#xff0c;不同的瀏覽器在解析網頁的方式、支持的技術標準等方面存在差異&#xff0c;這就導致了同一個網頁在不…

fpga bitstream userid

fpga version register # xdc 文件 set_property BITSTREAM.CONFIG.USERID "0xDEADC0DE" [current_design] set_property BITSTREAM.CONFIG.USR_ACCESS 0x66669999 [current_design]ug908 在bit下載之后的property可以看到 &#xff0c;GUI里面Tools → Edit Devic…

QT項目實戰:拼圖小游戲

一、拼圖智益-經典游戲&#xff08;開發環境&#xff09; 1&#xff1a;操作系統&#xff1a;Windows 10 x64專業版。 2&#xff1a;開發工具&#xff1a;Qt 5.12.8。 二、拼圖智益-經典游戲&#xff08;功能模塊&#xff09; 1&#xff1a;功能模塊1&#xff1a;游戲啟動…

1.1電路模型

1.1電路模型 任何實際電路由以下三部分組成&#xff1a; ①提供電能的能源 – 電源 ②用電裝置 – 負載 ③傳輸電能的金屬連線 – 導線 實際電路完成的功能&#xff1a;主要有以下兩個方面&#xff1a; &#xff08;1&#xff09;進行能量的產生、傳輸和轉換。&#xff08;如…

flash申請內存失敗,導致老化問題解決

背景 在閃光燈初始化階段客制化了一個buffer&#xff0c;下發到kernel的閃光燈驅動中用于保存讀取閃光燈寄存器的值。功能測試都是正常的&#xff0c;但是一旦開始批量跑產線老化測試會有1/4500左右概率的后主攝拍照卡住。定位根因是閃光燈初始化失敗&#xff0c;進一步原因就…

Django實現博客標簽字符串拆分功能

在Django模板中&#xff0c;可以使用自定義的模板過濾器來實現字符串的拆分。以下是一個簡單的示例&#xff0c;演示如何根據特定的分隔符拆分字符串并在模板中顯示。 首先&#xff0c;在Django應用的templatetags目錄中&#xff0c;創建一個Python模塊&#xff0c;例如extras…