數據結構基礎內容(第七篇:堆、哈夫曼樹)

# 堆 Heap ?

優先隊列(Priority Queue) ?

結構性:用 *數組* 表示的完全二叉樹; ?

有序性:任一結點的關鍵字是其子樹所有結點的最大值(或最小值) ?

? ? * “最大堆(MaxHeap)”,也稱“大頂堆”:最大值 ?

? ? * “最小堆(MinHeap)”,也稱“小頂堆” :最小值 ?

主要操作有: ?

? MaxHeap Create( int MaxSize ):創建一個空的最大堆。 ?

? Boolean IsFull( MaxHeap H ):判斷最大堆H是否已滿。 ?

? Insert( MaxHeap H, ElementType item ):將元素item插入最大堆H。 ?

? Boolean IsEmpty( MaxHeap H ):判斷最大堆H是否為空。 ?

? ElementType DeleteMax( MaxHeap H ):返回H中最大元素(高優先級)。 ?

## 結構

```c

typedef struct HNode *MaxHeap;

struct HNode {

? ? ElementType *Elements; // 存儲堆元素的數組

? ? int Size; ? // 堆的當前元素的個數

? ? int Capacity ?// 堆的最大容量

}

```

## 創建

```c

MaxHeap CreateHeap(int Maxsize)

{

? ? MaxHeap H = (MaxHeap)malloc(sizeof(struct HNode));

? ? H->Elements = malloc((MaxSize+1) * sizeof(ElementType)); // 因為這里是一個數組,需要分配空間

? ? H->Size = 0; // 當前是空的

? ? H->Capacity = MaxSize; ?// 堆的最大容量

? ? H->Elements[0] = MaxSize; /* 定義“哨兵”為大于堆中所有可能元素的值,便于以后操作 */

? ? return H;

}

```

## 插入

將新增結點插入到從其父結點到根結點的有序序列中 ?

將新item放在最后的位置Size+1, 然后跟他的父節點i/2比較,不斷把父節點往下(子節點)移動,直到其父節點大于item

```c

void InsertHeap(MaxHeap H, ElementType item)

{

? ? int i;

? ? if (IsFull(H)){

? ? ? ? printf("FULL\n");

? ? ? ? return;

? ? }

? ? i = ++H->Size; ?// H->Size++; i = H->Size; 把新增元素放在末尾H->Size++的位置上

? ? for(; H->Elements[i/2] < item; i/=2){ ?// 其父節點小于它

? ? ? ? H->Elements[i] = H->Elements[i/2]; // 把它的父節點,向下過濾, 插入的item向上過濾

? ? }

? ? // 當它的父結點[i/2]比它大的時候, 跳出循環

? ? H->Elements[i] = item; ?// 填上item

}


```

# 刪除 ?

取出根結點(最大值)元素,同時刪除堆的一個結點。 ?

* 最后的元素替補根的位置

* 有序化, 父結點和更大的那個子結點比較,將子結點不斷往上移, 直到父結點不子結點大 ?

```c

ElementType DeleteMax(MaxHeap H)

{

? ? int parent, child;

? ? ElementType MaxItem, temp;

? ? if(IsEmpty(H)){

? ? ? ? printf("Empty\n");

? ? ? ? return;

? ? }

? ? MaxItem = H->Elements[1]; // 取出最大值

? ? /* 用最大堆中最后一個元素從根節點開始向上過濾下層節點 */

? ? temp = H->Elements[Size]; ?// 把堆中最后一個值,交給temp

? ? Size--;

? ? for(parent=1; parent*2 <= H->Size; parent=child)

? ? {

? ? ? ? child = parent*2 ?// 左兒子

? ? ? ? /* child=左右兒子中大的那個, 當右兒子存在,且右兒子的值比左兒子大時,讓child=右兒子 */

? ? ? ? if((child!= H->Size) &&

? ? ? ? (H->Elements[child] < H->Elements[child+1]))

? ? ? ? ? ? child++;

? ? ? ?

? ? ? ? /* 當temp比child的值大時跳出循環 */

? ? ? ? if (temp >= Elements[child])

? ? ? ? ? ? break;

? ? ? ? else

? ? ? ? ? ? H->Elements[parent] = H->Elements[child]; //當parent < child,這個parent位置上變為child的值

? ? }

? ? H->Elements[parent] = temp;

? ? return MaxItem;

}

```

# 堆排序 ?

方法1:通過插入操作,將N個元素一個個相繼插入到一個初 始為空的堆中去,其時間代價最大為O(N logN)。

方法2:在線性時間復雜度下建立最大堆。O(N) ?

(1)將N個元素按輸入順序存入,先滿足完全二叉樹的結構特性 ?

(2)調整各結點位置,以滿足最大堆的有序特性。 ?

```c

void BuildHeap(MaxHeap H){

? ? int i;

? ? for(i = H->Size/2; i>0; i--)

? ? {// 從最后一個結點的父節點開始,到根節點為止

? ? ? ? PercDown(H, i);

? ? }

}

// 下濾函數, 將Maxheap中以H->Data[p]為根的子堆調整為最大堆

void PercDown( MaxHeap H, int p)

{

? ? int parent, child;

? ? X = H->Data[p]; // 取出根節點的值

? ? for(parent = ?p; parent*2 <= H->Size; parent = child)

? ? {

? ? ? ? child = parent * 2;

? ? ? ? if( (child != H->Size) && (H->Data[child] < H->Data[child+1]))

? ? ? ? {

? ? ? ? ? ? child++;

? ? ? ? }

? ? ? ? if (X > H->Data[child])

? ? ? ? ? ? break;

? ? ? ? else // 將X下濾

? ? ? ? ? ? H->Data[parent] = H->Data[child];

? ? }

? ? H->Data(parent) = X;

}

```

# 哈夫曼樹與哈夫曼編碼

帶權路徑WPL Weighted Path Length)長度最小, 最優二叉樹. ?

數據結構:

```c

typedef struct TreeNode *HuffmanTree;

struct TreeNode{

? ? int Weight;

? ? HaffmanTree left;

? ? HaffmantREE Right;

}

```

利用最小堆進行構造:

```c

HuffmanTree Huffman(MinHeap H)

{

? ? int i;

? ? HuffmanTree T;

? ? BuildMinHeap(H); // 將H->Elements[]按照權重調整為最小堆

? ? for(i=1; i < H->Size; i++) // 做size-1次合并

? ? {

? ? ? ? T = malloc(sizeof(struct TreeNode)); // 建立新結點

? ? ? ? /*從最小堆中刪除一個結點,作為新T的左子結點*/

? ? ? ? T->Left = DeleteMin(H);

? ? ? ? T->Right = DeleteMin(H);

? ? ? ? /*計算新權值*/

? ? ? ? T->Weight = T->Left->Weight+T->Right->Weight;

? ? ? ? Insert( H, T ); /*將新T插入最小堆*/

? ? }

? ? T = Deletemin(H); // 最小堆中的最后一個元素就是指向Huffman樹根節點的指針

? ? return T;

}

```

哈夫曼樹的特點:

1. 沒有度為1的結點

2. n個葉子結點的哈夫曼樹共有2n-1個結點; ?

? ? 因為: n2= n0 -1,

? ? 總結點數 = n0 + n2 = 2n0 - 1

3. 哈夫曼樹的任意非葉節點的左右子樹交換后仍是哈夫曼樹;

4. 對同一組權值{w1 ,w2 , ...... , wn},存在不同構的兩

# 集合及運算 ?

雙親表示法: 孩子指向父節點 ?

數據結構

```c

typedef struct

{

? ? ElementType Data;

? ? int Parent; ?// 其父節點的下標

} SetType;

```

## 查找某個元素所在的集合 ?

用根節點表示

```c

int Find(SetType S[], ElementType X)

{

? ? /* 在數組S中查找值為X的元素所屬的集合, MaxSize為數組最大長度 */

? ? int i;

? ? for(i=0; i<MaxSize && S[i].Data != X; i++)

? ? if (i >= MaxSize) // 未找到

? ? ? ? return -1;

? ? for(; S[i].Parent >= 0; i = s[i].Parent); ?// 向上找它的父節點

? ? return i;

}

```

## 集合的并運算 ?

如果它們不同根,則將其中一個根結點的父結點指針設置成

? ?另一個根結點的數組下標。

```c

void Union( SetType S[], ElementType X1, ElementType X2 )

{

? ? int Root1, Root2;

? ? Root1 = Find(S, X1);

? ? Root2 = Find(S, X2);

? ? if( Root1 != Root2 )

? ? ? ? S[Root2].Parent = Root1;

}

```

為了使樹更矮,合并時按秩合并 ?

直接用一個數組表示,不用之前的數據結構了

```c

#define MAXN 1000 ? ? ? ? ? ? ? ? ?/* 集合最大元素個數 */

typedef int ElementType; ? ? ? ? ? /* 默認元素可以用非負整數表示 */

typedef int SetName; ? ? ? ? ? ? ? /* 默認用根結點的下標作為集合名稱 */

typedef ElementType SetType[MAXN]; /* 假設集合元素下標從0開始 */

SetName Find(SetType S, ElementType X){

? ? for(; S[X] > 0; X=S[X]);

? ? return X.

}

void OldUnion(SetType S, SetName Root1, SetName Root2){

? ? S[Root2] = Root1;

}

void Union( SetType S, SetName Root1, SetName Root2 )

{ /* 這里默認Root1和Root2是不同集合的根結點 */

? ? /* 保證小集合并入大集合 */

? ? if ( S[Root2] < S[Root1] ) { /* 如果集合2比較大 */

? ? ? ? S[Root2] += S[Root1]; ? ? /* 集合1并入集合2 ?*/

? ? ? ? S[Root1] = Root2;

? ? }

? ? else { ? ? ? ? ? ? ? ? ? ? ? ? /* 如果集合1比較大 */

? ? ? ? S[Root1] += S[Root2]; ? ? /* 集合2并入集合1 ?*/

? ? ? ? S[Root2] = Root1;

? ? }

}

```

路徑壓縮

```c

SetName Find( SetType S, ElementType X )

{

? ? if ( S[X] < 0 ) /* 找到集合的根 */

? ? ? ? return X;

? ? else

? ? ? ? return S[X] = Find( S, S[X] ); /* 路徑壓縮 */

}

```

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

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

相關文章

CS231n-2017 Lecture7訓練神經網絡(二)筆記

本節主要是神經網絡的動態部分&#xff0c;也就是神經網絡學習參數和搜索最優超參數的過程梯度檢查&#xff1a;進行梯度檢查&#xff0c;就是簡單地把解析梯度與數值計算梯度進行比較&#xff0c;防止反向傳播的邏輯出錯&#xff0c;僅在調試過程中使用。有如下技巧 &#xff…

IntelliJ IDEA 中左上方未顯示項目根目錄問題

問題&#xff1a; 在IDEA中編寫代碼時&#xff0c;發現左上方只顯示項目的子模塊&#xff0c;未顯示根項目名稱。 如圖所示&#xff0c;未顯示子模塊的根項目&#xff1a;問題分析 頂層根目錄未被識別為項目根目錄&#xff0c;需要手動添加識別。 問題解決 進入File – Project…

OpenCV 圖像變換全解析:從鏡像翻轉到仿射變換的實踐指南

前言處理圖像時&#xff0c;翻轉、旋轉、平移等操作很常用。OpenCV 提供了簡單的方法實現這些變換&#xff0c;本文帶你快速學會用它做圖像翻轉和仿射變換。1 圖像翻轉(圖像鏡像旋轉)在OpenCV中&#xff0c;圖片的鏡像旋轉是以圖像的中心為原點進行鏡像翻轉的。cv2.flip(img,fl…

【運維】Linux運維命令記錄

重置root密碼使用命令重新設置一下root賬戶的密碼 passwd root根據提示設置一下密碼&#xff0c;然后使用sudo -i 時輸入密碼就可以切換到root賬戶了ssh登陸以后&#xff0c;要用sudo -i命令給用戶提權&#xff0c;提到超級管理員&#xff0c;然后輸入密碼才有用

PandasAI連接LLM進行智能數據分析

1. 引言 Pandas是一個數據分析開源組件庫&#xff0c;提供了高性能、易用的數據結構和數據分析工具。它的核心的功能是其DataFrame對象&#xff0c;這是一個帶有行和列標簽的二維表格數據結構&#xff0c;支持缺失數據處理、時間序列功能、靈活的數據輸入輸出方法、數據對齊和…

Spring之【Bean的生命周期】

目錄 1、生成BeanDefinition BeanDefinitionRegistry接口 DefaultListableBeanFactory實現類 2、合并BeanDefnition AbstractBeanFactory類 3、BeanFactoryPostProcessor的方法回調 AbstractApplicationContext類 PostProcessorRegistrationDelegate類 4、BeanPostPro…

搜狐新聞直播間適配HarmonyOs實現點贊動畫

01背景介紹隨著新聞客戶端鴻蒙單框架系統適配工作的推進&#xff0c;從原來的基礎功能到現在已經適配全功能的85%以上。與此同時&#xff0c;我們也在持續深入挖掘鴻蒙系統的特性&#xff0c;以提升整體應用的質量與用戶體驗。在這一過程中&#xff0c;動畫作為增強交互與視覺體…

83、設置有人DTU設備USR-M100采集傳感器數據,然后上傳阿里云服務

基本思想:設置M100 采集傳感器數據 一、首先將DTU設備USR-M100連接路由器上,然后使用python代碼搜索同一局域網設備, import platform import sys import os import time import threadinglive_ip = 0def get_os():os = platform.system()if os == "Windows":re…

P1019 [NOIP 2000 提高組] 單詞接龍

題目描述單詞接龍是一個與我們經常玩的成語接龍相類似的游戲&#xff0c;現在我們已知一組單詞&#xff0c;且給定一個開頭的字母&#xff0c;要求出以這個字母開頭的最長的“龍”&#xff08;每個單詞都最多在“龍”中出現兩次&#xff09;&#xff0c;在兩個單詞相連時&#…

詳解力扣高頻SQL50題之1633. 各賽事的用戶注冊率【簡單】

傳送門&#xff1a;1633. 各賽事的用戶注冊率 題目 用戶表&#xff1a; Users -------------------- | Column Name | Type | -------------------- | user_id | int | | user_name | varchar | -------------------- user_id 是該表的主鍵(具有唯一值的列)。 該表中的每行包…

FROM stakater/java8-alpine 構建cocker鏡像

在 Dockerfile 中&#xff0c;FROM stakater/java8-alpine 是第一條也是最核心的指令&#xff0c;它定義了構建新鏡像所基于的「基礎鏡像」。以下是逐層解析&#xff1a;&#x1f50d; 關鍵字拆解 1. FROM —— 起點指令 ? 作用&#xff1a;聲明當前鏡像的起點&#xff08;父鏡…

Word2Vec模型訓練全流程解析:從數據預處理到實體識別應用

請添加圖片描述 訓練Word2Vec模型 概述 問題 我們如何訓練Word2Vec模型&#xff1f;在特定數據集上訓練Word2Vec模型何時是有利的&#xff1f; 目標 理解在自有數據上訓練Word2Vec模型而非使用預訓練模型的優勢 Colab環境配置 運行以下代碼以啟用輔助函數并重新讀取數據…

在Ubuntu上使用QEMU學習RISC-V程序(2)gdb調試

文章目錄一、準備工作二、基本調試流程1. 設置斷點2. 執行程序3. 查看源代碼/匯編三、查看寄存器1. 查看通用寄存器2. 查看特殊寄存器四、查看內存1. 內存查看命令2. 內存修改命令五、調試實戰示例六、高級調試技巧1. 條件斷點2. 自動顯示3. 內存斷點&#xff08;觀察點&#x…

不止于“亮”:一盞智慧路燈的技術進化史——塔能科技用“落地性”定義行業標準

在凌晨3點的園區道路之上&#xff0c;路燈會隨著車輛的靠近而自動亮起&#xff0c;待車輛逐漸遠去之后&#xff0c;又會緩緩地調暗下來&#xff1b;當電纜意外被觸碰的時候&#xff0c;系統能夠在短短3秒之內自動發出報警信息&#xff0c;并且推送出維修工單&#xff1b;而當一…

Redis的String數據類型底層實現

redis就是用c語言寫&#xff0c;但redis的string并沒有直接用c語言的string&#xff0c;而是自己搞了一個 SDS 結構體來表示字符串。SDS 的全稱是 Simple Dynamic String&#xff0c;中文叫做“簡單動態字符串”。想知道為什么這么做&#xff0c;我們先看看c語言的string是什么…

【音視頻學習】四、深入解析視頻技術中的YUV數據存儲方式:從原理到實踐

文章目錄 引言 1. YUV 基礎:為什么它比 RGB 更適合視頻? 1.1 YUV 與 RGB 的核心區別 1.2 YUV色度下采樣簡介 2. YUV 的三大存儲方式 方式一:平面格式(Planar) 方式二:半平面格式(Semi-Planar ) 方式三:打包格式(Packed YUV) 三種存儲方式對比: 3. 如何選擇合適的 Y…

前端項目組成

一、前端項目常見模塊及功能&#xff08;以 Vue/React 通用結構為例&#xff09; 前端項目的模塊本質是「按功能拆分的代碼文件/文件夾」&#xff0c;就像蓋房子的「磚、梁、窗」各司其職&#xff1a;模塊類型功能說明&#xff08;大白話&#xff09;舉個例子pages&#xff08;…

聚觀早報 | 猿編程推動中美青少年AI實踐;華為Pura 80數字版售價公布;iPhone 17 Air電池曝光

聚觀早報每日整理最值得關注的行業重點事件&#xff0c;幫助大家及時了解最新行業動態&#xff0c;每日讀報&#xff0c;就讀聚觀365資訊簡報。整理丨肖羽7月24日消息猿編程推動中美青少年AI實踐華為Pura 80數字版售價公布iPhone 17 Air電池曝光亞馬遜收購AI初創公司Bee蜂巢半固…

unittest 案例執行順序詳解

unittest 案例執行順序詳解在 unittest 框架中&#xff0c;測試用例的執行順序有默認規則&#xff0c;也可通過自定義方式調整。以下是具體說明&#xff1a;一、默認執行順序規則unittest 對測試用例的執行順序遵循 “按測試方法名的 ASCII 碼排序” 原則&#xff0c;具體邏輯如…

【web大前端】001_前端開發入門:創建你的第一個網頁

前端開發入門&#xff1a;創建你的第一個網頁 在當今數字化時代&#xff0c;網頁已經成為人們獲取信息和交流的重要平臺。對于想要學習編程的人來說&#xff0c;前端開發往往是一個不錯的起點。本文將帶你通過簡單的兩步&#xff0c;創建屬于你的第一個網頁程序。 點擊這里去…