堆概念和結構

1. 二叉樹的順序結構

普通的二叉樹是不適合用數組來存儲的,因為可能會存在大量的空間浪費。而完全二叉樹更適合使用順序結構存儲。現實中通常 把堆使用順序結構的數組來存儲 ,需要注意的是這里的堆和操作系統虛擬進程地址空間中的堆是兩回事,一個是數據結構(完全二叉樹),一個是操作系統中管理內存區域分段。

順序存儲

2. 堆的概念

堆是將數組數據看作一顆完全二叉樹。遞增遞減數組一定是堆,堆不一定是遞增遞減數組。在實際意義中,堆可以實現堆排序,時間復雜度是 O(N*longN) ,提高查找效率,解決top k問題。

堆的性質:

1)堆總是一棵完全二叉樹

2)堆中某個節點的值總是不大于或不小于其父節點的值

3. 堆的分類

堆可以分為大堆和小堆:

大堆要求: 任意一個父親 <= 孩子

小堆要求: 任意一個父親 >= 孩子

堆

4. 堆的實現(數組小堆)

這里將著重利用父子節點之間的關系完成堆的構建以及各類接口的實現:

leftchild = parent*2+1	# 奇數
rightchild = parent*2+2	# 偶數
parent = (child-1)/2	# 不區分左右孩子

如果要實現大堆,就將對應的向下調整算法和向上調整算法的判定更改即可實現。下面將其分為3個模塊進行實現小堆Heap.h,Heap.c,test.c

4.1 接口設計(Heap.h)

堆的結構設計和順序表類似,這里將采用小堆進行設計接口,對堆插入數據時,就要按照堆的規則進行構建。需要注意的是,堆的刪除是刪除跟節點數據。

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>typedef int HPDataType;typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;void HeapInit(HP* php);
void HeapDestory(HP* php);
// 小堆
// 插入,時間復雜度是O(logN)
void HeapPush(HP* php, HPDataType x);
// 規定刪除堆頂,即根節點
// 挪動數據覆蓋刪除跟會出問題
void HeapPop(HP* php);
HPDataType HeapTop(HP* php);
size_t HeapSize(HP* php);
bool HeapEmpty(HP* php);

4.2 接口實現(Heap.c)

1)初始化銷毀

void HeapInit(HP* php)
{assert(php);php->a = NULL;php->capacity = php->size = 0;
}void HeapDestory(HP* php)
{assert(php);free(php->a);php->a = NULL;php->capacity = php->size = 0;
}

2)插入,時間復雜度是O(logN)

因為擴容操作只有 HeapPush 使用,因此不將其作為單獨函數。

插入的過程中要保證堆符合大堆或者小堆的規則,因此,要對其進行調整,這里將引入向上調整算法,并將其作為單獨函數。

向上調整算法主要利用父子下標的特性, 在數據插入成為葉子時,將其與父節點比較,直到滿足堆的規則 (這里小堆要滿足父節點小于等于子節點 )

插入

void AdjustUp(HPDataType* a, int child)
{int parent = (child - 1) / 2;while (child > 0){if (a[child] < a[parent]){Swap(&a[child], & a[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}// 插入,時間復雜度是O(logN)
void HeapPush(HP* php, HPDataType x)
{assert(php);if (php->size == php->capacity){int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;HPDataType* tmp = (HPDataType*)realloc(php->a, newCapacity * sizeof(HPDataType));if (tmp == NULL){perror("realloc fail\n");exit(-1);}php->a = tmp;php->capacity = newCapacity;}php->a[php->size] = x;php->size++;AdjustUp(php->a, php->size - 1);
}

因為后續要重復進行交換,所以將其作為單獨一個函數

void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}

3)刪除,規定刪除堆頂,即根節點

刪除是刪頭,可以選出最大最小的數據,尾刪沒有多大意義。

有人會想到挪動數據覆蓋刪除根節點,但會出問題,而且數組不一定有序,挪動后整棵樹的父子關系就會全亂了,并且也可能就不是堆了。

因此,這里采用的辦法是首先進行首尾交換,然后尾刪,這樣左右子樹依舊是小堆,然后再用向下調整算法,從而將堆構建完成。

刪除

void AdjustDown(HPDataType* a, int size, int parent)
{int child = parent * 2 + 1;while (child < size){if (child + 1 < size && a[child] > a[child + 1]){child++;}if (a[child] < a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}void HeapPop(HP* php)
{assert(php);// 空assert(php->size > 0);Swap(&php->a[0], &php->a[php->size - 1]);// 不需要進行覆蓋php->size--;AdjustDown(php->a, php->size, 0);
}

4)堆頂數據、堆大小、堆空

這三個操作就相對簡單,返回堆頂元素要檢查堆是否為空。

HPDataType HeapTop(HP* php)
{assert(php);// 空assert(php->size > 0);return php->a[0];
}size_t HeapSize(HP* php)
{assert(php);return php->size;
}bool HeapEmpty(HP* php)
{assert(php);return php->size == 0;
}

4.3 完整代碼

Heap.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>typedef int HPDataType;typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;void HeapInit(HP* php);
void HeapDestory(HP* php);
// 小堆
// 插入,時間復雜度是O(logN)
void HeapPush(HP* php, HPDataType x);
// 規定刪除堆頂,即根節點
// 挪動數據覆蓋刪除跟會出問題
void HeapPop(HP* php);
HPDataType HeapTop(HP* php);
size_t HeapSize(HP* php);
bool HeapEmpty(HP* php);

Heap.c

#include "Heap.h"// 初始化銷毀
void HeapInit(HP* php)
{assert(php);php->a = NULL;php->capacity = php->size = 0;
}void HeapDestory(HP* php)
{assert(php);free(php->a);php->a = NULL;php->capacity = php->size = 0;
}// 實現小堆
void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}void AdjustUp(HPDataType* a, int child)
{int parent = (child - 1) / 2;while (child > 0){if (a[child] < a[parent]){Swap(&a[child], & a[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}// 插入,時間復雜度是O(logN)
void HeapPush(HP* php, HPDataType x)
{assert(php);if (php->size == php->capacity){int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;HPDataType* tmp = (HPDataType*)realloc(php->a, newCapacity * sizeof(HPDataType));if (tmp == NULL){perror("realloc fail\n");exit(-1);}php->a = tmp;php->capacity = newCapacity;}php->a[php->size] = x;php->size++;AdjustUp(php->a, php->size - 1);
}// 規定刪除堆頂,即根節點
// 挪動數據覆蓋刪除跟會出問題
void AdjustDown(HPDataType* a, int size, int parent)
{int child = parent * 2 + 1;while (child < size){if (child + 1 < size && a[child] > a[child + 1]){child++;}if (a[child] < a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}void HeapPop(HP* php)
{assert(php);// 空assert(php->size > 0);Swap(&php->a[0], &php->a[php->size - 1]);php->size--;AdjustDown(php->a, php->size, 0);
}HPDataType HeapTop(HP* php)
{assert(php);// 空assert(php->size > 0);return php->a[0];
}size_t HeapSize(HP* php)
{assert(php);return php->size;
}bool HeapEmpty(HP* php)
{assert(php);return php->size == 0;
}

test.c

#include "Heap.h"int main()
{int a[] = { 2,7,0,21,56,786,1,3 };HP hp;HeapInit(&hp);for (int i = 0; i < sizeof(a) / sizeof(int); i++){HeapPush(&hp, a[i]);}int k = 7;printf("打印小堆頂前7個數據:\n");while (k--){printf("%d ", HeapTop(&hp));HeapPop(&hp);}printf("\n堆大小為:%d, 堆是否為空:%d\n", HeapSize(&hp), HeapEmpty(&hp));printf("銷毀小堆!\n");HeapDestory(&hp);return 0;
}

運行效果

運行效果
在學會堆的知識后,我們應該怎么應用呢?
下面將介紹兩個使用的堆使用:
堆排序&TopK問題:堆的實際應用:堆排序&TopK問題

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

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

相關文章

VUE的腳手架搭建引入類庫

VUE的小白腳手架搭建 真的好久好久自己沒有發布自己博客了,對于一直在做后端開發的我 ,由于社會卷啊卷只好學習下怎么搭建前端,一起學習成長吧~哈哈哈(最終目的,能夠懂并簡易開發) 文章目錄 VUE的小白腳手架搭建1.下載node.js2.安裝vue腳手架3.創建一個項目4.代碼規范約束配置(…

使用 Arduino 和 ThingSpeak 通過互聯網進行實時溫度和濕度監測

使用 ThingSpeak 和 Arduino 通過 Internet 進行溫度和濕度監控 濕度和溫度是許多地方(如農場、溫室、醫療、工業家庭和辦公室)非常常見的測量參數。我們已經介紹了使用 Arduino 進行濕度和溫度測量,并在 LCD 上顯示數據。 在這個物聯網項目中,我們將使用ThingSpeak在互聯…

論文分享:PL-ALF框架實現無人機低紋理環境自主飛行

在室內倉庫、地下隧道等低紋理復雜場景中&#xff0c;無人機依賴視覺傳感器進行自主飛行時&#xff0c;往往會遇到定位精度低、路徑規劃不穩定等難題。針對這一問題&#xff0c;重慶郵電大學計算機學院雷大江教授團隊在IEEE Trans期刊上提出了一種新型自主飛行框架&#xff1a;…

[Java實戰]性能優化qps從1萬到3萬

一、問題背景 ? 事情起因是項目上springboot項目提供的tps達不到客戶要求,除了增加服務器提高tps之外,作為團隊的技術總監,架構師,技術扛把子,本著我不入地獄誰入地獄的原則,決心從代碼上優化,讓客戶享受到飛一般的感覺。雖然大多數編程工作在寫下第一行代碼時已經完成…

如何篩選能實現共享自助健身房“靈活性”的物聯網框架?

共享自助健身房已經成為一種新興的健身方式&#xff0c;這種模式方便快捷&#xff0c;尤其適合i人健身愛好者&#xff0c;市場接受度還是挺好的。對于無人自助式的健身房要想實現靈活性&#xff0c;要挑選什么樣的物聯網框架呢&#xff1f; 1. 支持多種通信協議 共享自助健身…

【后端】【django】拋棄 Django 自帶用戶管理后,能否使用 `simple-jwt`?

拋棄 Django 自帶用戶管理后&#xff0c;能否使用 simple-jwt&#xff1f; 一、結論 是的&#xff0c;即使拋棄了 Django 自帶的用戶管理&#xff08;AbstractUser 或 AbstractBaseUser&#xff09;&#xff0c;仍然可以使用 django-rest-framework-simplejwt&#xff08;簡稱…

【量化科普】Correlation,相關性

【量化科普】Correlation&#xff0c;相關性 &#x1f680;量化軟件開通 &#x1f680;量化實戰教程 在量化投資領域&#xff0c;相關性&#xff08;Correlation&#xff09;是一個核心概念&#xff0c;用于衡量兩個變量之間的線性關系強度和方向。簡單來說&#xff0c;它告…

大數據學習(68)- Flink和Spark Streaming

&#x1f34b;&#x1f34b;大數據學習&#x1f34b;&#x1f34b; &#x1f525;系列專欄&#xff1a; &#x1f451;哲學語錄: 用力所能及&#xff0c;改變世界。 &#x1f496;如果覺得博主的文章還不錯的話&#xff0c;請點贊&#x1f44d;收藏??留言&#x1f4dd;支持一…

MCU詳解:嵌入式系統的“智慧之心”

在現代電子設備中&#xff0c; MCU&#xff08;Microcontroller Unit&#xff0c;微控制器&#xff09;扮演著至關重要的角色。從智能家居到工業控制&#xff0c;從汽車電子到醫療設備&#xff0c;MCU以其小巧、低功耗和高集成度的特點&#xff0c;成為嵌入式系統的核心組件。 …

(鏈表)24. 兩兩交換鏈表中的節點

給你一個鏈表&#xff0c;兩兩交換其中相鄰的節點&#xff0c;并返回交換后鏈表的頭節點。你必須在不修改節點內部的值的情況下完成本題&#xff08;即&#xff0c;只能進行節點交換&#xff09;。 示例 1&#xff1a; 輸入&#xff1a;head [1,2,3,4] 輸出&#xff1a;[2,1,4…

吳恩達機器學習筆記復盤(三)Jupyter NoteBook

Jupyter NoteBook Jupyter是一個開源的交互式計算環境&#xff1a; 特點 交互式編程&#xff1a;支持以單元格為單位編寫和運行代碼&#xff0c;用戶可以實時看到代碼的執行結果&#xff0c;便于逐步調試和理解代碼邏輯。多語言支持&#xff1a;不僅支持Python&#xff0c;還…

【Linux】從互斥原理到C++ RAII封裝實踐

&#x1f4e2;博客主頁&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;歡迎點贊 &#x1f44d; 收藏 ?留言 &#x1f4dd; 如有錯誤敬請指正&#xff01; &#x1f4e2;本文由 JohnKi 原創&#xff0c;首發于 CSDN&#x1f649; &#x1f4e2;未來很長&#…

微服務無狀態服務設計

微服務無狀態服務設計是構建高可用、高擴展性系統的核心方法。 一、核心設計原則 請求獨立性 每個請求必須攜帶完整的上下文信息&#xff0c;服務不依賴本地存儲的會話或用戶數據。例如用戶認證通過JWT傳遞所有必要信息&#xff0c;而非依賴服務端Session。 狀態外置化 將會話…

30、map 和 unordered_map的區別和實現機制【高頻】

底層結構 map底層是紅黑樹結構&#xff0c;而unordered_map底層是哈希結構; 有序性 但是紅黑樹其實是一種二叉搜索樹&#xff0c;插入刪除時會自動排序hash因為是把數據映射到數組上的&#xff0c;而且存在哈希沖突&#xff0c;所以不能保證有序存儲 所以有序存儲使用map&a…

大數據-spark3.5安裝部署之local模式

spark&#xff0c;一個數據處理框架和計算引擎。 下載 local模式即本地模式&#xff0c;就是不需要任何其他節點資源就可以在本地執行spark代碼的環境。用于練習演示。 上傳解壓 使用PortX將文件上傳至/opt 進入/opt目錄&#xff0c;創建目錄module&#xff0c;解壓文件至/o…

Manus “Less structure,More intelligence ”獨行云端處理器

根據市場調研機構Statista數據顯示&#xff0c;全球的AR/AR的市場規模預計目前將達到2500億美元&#xff0c;Manus作為VR手套領域的領軍企業&#xff0c;足以顛覆你的認知。本篇文章將帶你解讀Manus產品&#xff0c;針對用戶提出的種種問題&#xff0c;Manus又將如何解決且讓使…

Oracle數據庫存儲結構--邏輯存儲結構

數據庫存儲結構&#xff1a;分為物理存儲結構和邏輯存儲結構。 物理存儲結構&#xff1a;操作系統層面如何組織和管理數據 邏輯存儲結構&#xff1a;Oracle數據庫內部數據組織和管理數據&#xff0c;數據庫管理系統層面如何組織和管理數據 Oracle邏輯存儲結構 數據庫的邏…

芯驛電子 ALINX 亮相德國紐倫堡,Embedded World 2025 精彩回顧

2025年3月13日&#xff0c;全球規模最大的嵌入式行業盛會——德國紐倫堡國際嵌入式展&#xff08;embedded world 2025&#xff09;圓滿落幕。 在這場匯聚全球 950 家展商、3 萬余專業觀眾的科技盛宴中&#xff0c;芯驛電子 ALINX 展位人頭攢動&#xff0c;多款尖端產品吸引客戶…

Nexus File類型Blob Stores遷移至Minio操作指南(上)

#作者&#xff1a;閆乾苓 文章目錄 目的前期準備查看file類型Blob Stores數據目錄位置aws cli客戶端連接工具OrientDB cli客戶端連接工具在minio中新建 bucket 目的 增強nexus構件數據的高可用性和擴展性 前期準備 查看并記錄需要遷移的Blob Store及repository 查看fil…

藍橋杯嵌入式組第十二屆省賽題目解析+STM32G431RBT6實現源碼

文章目錄 1.題目解析1.1 分而治之&#xff0c;藕斷絲連1.2 模塊化思維導圖1.3 模塊解析1.3.1 KEY模塊1.3.2 LED模塊1.3.3 LCD模塊1.3.4 TIM模塊1.3.5 UART模塊1.3.5.1 uart數據解析 2.源碼3.第十二屆題目 前言&#xff1a;STM32G431RBT6實現嵌入式組第十二屆題目解析源碼&#…