【數據結構】【C語言】堆~動畫超詳細解讀!

目錄

    • 1 什么是堆
      • 1.1 堆的邏輯結構和物理結構
      • 1.2 堆的訪問
      • 1.3 堆為什么物理結構上要用數組?
      • 1.4 堆數據上的特點
    • 2 堆的實現
      • 2.1 堆類型定義
      • 2.2 需要實現的接口
      • 2.3 初始化堆
      • 2.4 銷毀堆
      • 2.5 堆判空
      • 2.6 交換函數
      • 2.7 向上調整(小堆)
      • 2.8 向下調整(小堆)
      • 2.9 堆插入
      • 2.10 堆刪除
      • 2.11 //堆頂
    • 3 完整代碼
      • 3.1 heap.h
      • 3.2 heap.c

1 什么是堆

  • 簡單來說堆是二叉樹的一種表示方式,它在邏輯上就是一顆完全二叉樹,它在物理上卻是一個數組,這么說可能有點抽象,我們原來學習的棧,隊列,或者說順序表,鏈表等等,他們的邏輯結構和物理結構是相同或者相似的,就會比較好理解一些,而在堆這里物理結構和邏輯結構截然不同,理解相對就會比較抽象一些,我們接著看

1.1 堆的邏輯結構和物理結構

  • 邏輯結構即我們想象的結構,就比方說我們早上在圖書館排隊的時候,放個包在圖書館門口,人可能都不見了,這個時候我們邏輯上認為我們在排隊,但物理上我們同學就可能在吃早飯上廁所啥的
  • 邏輯上我們想象這個數組是一個二叉樹,并且像二叉樹一樣訪問子節點或者父節點
  • 比方說我給出以下數組,它在邏輯上是這樣表示的(當然哈,指針其實是不存在的,只是邏輯上我們看作其是父子關系):
    請添加圖片描述

1.2 堆的訪問

  • 既然堆是一顆貨真價實的二叉樹,可我們怎么像二叉樹一樣,通過父/子節點訪問子/父節點呢?

在這里插入圖片描述

  1. 通過父節點訪問子節點:
    • 我們假設父節點的下標為3,我們想訪問它的子節點,只需要把 父節點的下標 * 2 + 1父節點的下標 * 2 + 2 即可 即 7 或 8
  2. 通過子節點訪問父節點
    • 我們假設子節點的下標為7,我們想訪問它的父節點,只需要把 (子節點的下標 - 1) / 2 即可 即 3
    • 我們假設子節點的下表為8,我們想訪問它的父節點,依舊只需要把 (子節點的下標 - 1) / 2 即可 依舊是 3

1.3 堆為什么物理結構上要用數組?

  • 事實上學習堆是為了學習堆排序打基礎,在堆排序中,有時候需要頻繁交換頭尾節點,如果用數組,找節點就會方便很多,交換函數也很好寫,效率會更高,用鏈表要不斷去遍歷,或者專門寫個尾指針妥協,很沒必要
  • 其次,如果我們用鏈式存儲的話,訪問子/父節點需要定義3個指針,需要多開辟很多空間
  • 堆一定是完全二叉樹,用數組存放會很方便,其中不會有空節點,所有數據存儲都是連續的

1.4 堆數據上的特點

  • 堆必須要始終滿足滿足:父節點值比子節點小或者父節點始終比子節點大
  • 我們稱父節點值始終比子節點小的堆為小堆/小根堆
  • 我們稱父節點值始終比子節點大的堆為大堆/大根堆

例如:
1.大堆:
在這里插入圖片描述

2.小堆:
在這里插入圖片描述

2 堆的實現

2.1 堆類型定義

//堆在物理上是一個數組,我們直接按數組的定義方式就行
//類型定義
typedef int HPDataType;typedef struct Heap 
{HPDataType* data;int size;int capa;
}Heap;

2.2 需要實現的接口

//交換函數
void Swap(HPDataType* x, HPDataType* y);//向上調整(小堆)
void AdjustUp(HPDataType* data, int child);//向下調整(小堆)
void AdjustDown(HPDataType* data, int size, int father);//初始化堆
void HPInit(Heap* php);//銷毀堆
void HPDestroy(Heap* php);//堆插入
void HPPush(Heap* php, HPDataType x);//堆刪除
void HPPop(Heap* php);//堆頂
HPDataType HPTop(Heap* php);//堆判空
bool HPEmpty(Heap* php);

2.3 初始化堆

//像順序表一樣初始化就行
//初始化堆
void HPInit(HP* php)
{assert(php);php->a = (HPdatatype*)calloc(4, sizeof(HPdatatype));if (php->a == NULL){perror("HPInit::calloc fail");exit(1);}php->capa = 4;php->size = 0;
}

2.4 銷毀堆

//同樣,像順序表一樣銷毀就行
//銷毀堆
void HPdestory(HP* php)
{assert(php);free(php->a);php->a = NULL;php->capa = 0;php->size = 0;
}

2.5 堆判空

//堆判空
bool HPEmpty(HP* php)
{assert(php);   //判空return php->size == 0;    //size是0就返回true
}

2.6 交換函數

//只是完成數據在空間上的交換
//交換函數
void Swap(HPdatatype* x, HPdatatype* y)
{HPdatatype tmp = *x;*x = *y;*y = tmp;
}

2.7 向上調整(小堆)

  • 注意這里是重點
  • 向上調整會在很多地方用到,基本思想就是讓本應該在上面的節點往上挪
//向上調整(小堆)
void AdjustUp(HPdatatype* a, int child)
{assert(a);//判空int father = (child - 1) / 2;//推算出父節點的位置while (father < child && a[father] > a[child])      //只要子節點比父節點還小,就讓子節點和父節點交換{								               		//重復此步驟直到子節點大于父節點或者子節點和自己比較Swap(&a[child], &a[father]); child = father;father = (child - 1) / 2;}
}

請添加圖片描述

2.8 向下調整(小堆)

  • 注意這里是重點
  • 向下調整同樣會在很多地方用到
//向下調整(小堆)
void AdjustDown(HPdatatype* a, int size, int father)
{assert(a);//判空int child = (father * 2) + 1;      //先假設比較小的是左子節點if (child + 1 < size && a[child] > a[child + 1])        //如果右子節點比左子節點大,注意要判斷一下子節點是否會超范圍{child++;        //把child改成右子節點}while (child < size && a[father] > a[child] )    //如果父節點一直比子節點大就不斷交換下移{                                                //直到子節點超出size范圍或者父節點比子節點小就停下Swap(&a[father], &a[child]);     //交換father = child;              //重新找到父節點(交換后的父節點應該是原來的子節點的位置)child = (father * 2) + 1;    //重新定位子節點if (child + 1 < size && a[child] > a[child + 1])    //如法炮制{child++;}}
}

請添加圖片描述

2.9 堆插入

  • 堆插入一般插入到末尾,因為末尾很空,啥也沒有,比較好插入,插在其他地方還得先挪動才可以插入
//堆插入
void HPPush(HP* php, HPdatatype x)
{assert(php);   //判空//堆擴容,這里像數組一樣擴容就行if (php->capa == php->size){HPdatatype* tmp = (HPdatatype*)realloc(php->a, 2 * php->size * sizeof(HPdatatype));if (tmp == NULL){perror("HPPush::realloc fail");exit(1);}php->a = tmp;php->capa *= 2;}php->a[php->size] = x;    //將要插入的數據放到堆低AdjustUp(php->a, php->size);      //通過向上調整找到這個數據本應該在的位置php->size++;      //別忘了讓size++
}

2.10 堆刪除

  • 堆刪除一般刪除堆頂的數據,但不能簡單地把堆頂置為空,而是要和末尾數據交換,再一點點下調
//堆刪除
void HPPop(HP* php)
{assert(php);     //判空if (!HPEmpty(php))    //如果堆不是空堆{Swap(&php->a[0], &php->a[php->size - 1]);   //交換堆頂和末尾的數據AdjustDown(php->a, php->size - 1, 0);    //將堆頂的數據向下挪到合適的位置php->size--;   //別忘了size--}
}

2.11 //堆頂

//取堆頂
HPdatatype HPTop(HP* php)
{assert(php);    //判空return HPEmpty(php) ? -1 : php->a[0];   //返回堆頂數據
}

  • 完整代碼在最下面哦

佬!都看到這了,如果覺得有幫助的話一定要點贊啊佬 >v< !!!
放個卡密在這,感謝各位能看到這兒啦!
請添加圖片描述


3 完整代碼

3.1 heap.h

#pragma once//頭文件聲明
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <string.h>//類型定義
typedef int HPdatatype;typedef struct Heap
{HPdatatype* a;int size;int capa;
}HP;//函數申明//交換函數
void Swap(HPDataType* x, HPDataType* y);//向上調整(小堆)
void AdjustUp(HPDataType* data, int child);//向下調整(小堆)
void AdjustDown(HPDataType* data, int size, int father);//初始化堆
void HPInit(Heap* php);//銷毀堆
void HPDestroy(Heap* php);//堆插入
void HPPush(Heap* php, HPDataType x);//堆刪除
void HPPop(Heap* php);//堆頂
HPDataType HPTop(Heap* php);//堆判空
bool HPEmpty(Heap* php);

3.2 heap.c

#include "heap.h"//初始化堆
void HPInit(HP* php)
{assert(php);php->a = (HPdatatype*)calloc(4, sizeof(HPdatatype));if (php->a == NULL){perror("HPInit::calloc fail");exit(1);}php->capa = 4;php->size = 0;
}//銷毀堆
void HPdestory(HP* php)
{assert(php);free(php->a);php->a = NULL;php->capa = 0;php->size = 0;
}//堆判空
bool HPEmpty(HP* php)
{assert(php);return php->size == 0;
}//取堆頂
HPdatatype HPTop(HP* php)
{assert(php);return HPEmpty(php) ? -1 : php->a[0];
}//交換
void Swap(HPdatatype* x, HPdatatype* y)
{HPdatatype tmp = *x;*x = *y;*y = tmp;
}//向上調整(小堆)
void AdjustUp(HPdatatype* a, int child)
{assert(a);int father = (child - 1) / 2;while (father < child && a[father] > a[child]){Swap(&a[child], &a[father]);child = father;father = (child - 1) / 2;}
}//堆插入
void HPPush(HP* php, HPdatatype x)
{assert(php);//堆擴容if (php->capa == php->size){HPdatatype* tmp = (HPdatatype*)realloc(php->a, 2 * php->size * sizeof(HPdatatype));if (tmp == NULL){perror("HPPush::realloc fail");exit(1);}php->a = tmp;php->capa *= 2;}php->a[php->size] = x;AdjustUp(php->a, php->size);php->size++;
}//向下調整(小堆)
void AdjustDown(HPdatatype* a, int size, int father)
{assert(a);int child = (father * 2) + 1;if (child + 1 < size && a[child] > a[child + 1]){child++;}while (child < size && a[father] > a[child] ){Swap(&a[father], &a[child]);father = child;child = (father * 2) + 1;if (child + 1 < size && a[child] > a[child + 1]){child++;}}
}//堆刪除
void HPPop(HP* php)
{assert(php);if (!HPEmpty(php)){Swap(&php->a[0], &php->a[php->size - 1]);AdjustDown(php->a, php->size - 1, 0);php->size--;}
}

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

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

相關文章

微服務項目收獲和總結---第2,3天(分庫分表思想,文章業務)

①分庫分表思想 文章表一對一為什么要拆分&#xff1f;因為文章的內容會非常大&#xff0c;查詢效率會很低&#xff0c;我們經常操作文章的基本信息&#xff0c;不會很經常查詢文章內容。充分發揮高頻數據的操作效率。 ②freemarker和minIO 由于文章內容數據量過大&#xff0c…

git clone 出現的問題

問題: core源碼ref新API % git clone https://github.com/xxxx.git Cloning into core... remote: Enumerating objects: 58033, done. remote: Counting objects: 100% (1393/1393), done. remote: Compressing objects: 100% (750/750), done. error: 432 bytes of body are …

辦公自動化-Python如何提取Word標題并保存到Excel中?

辦公自動化-Python如何提取Word標題并保存到Excel中&#xff1f; 應用場景需求分析實現思路實現過程安裝依賴庫打開需求文件獲取word中所有標題去除不需要的標題創建工作簿和工作表分割標題功能名稱存入測試對象GN-TC需求標識符存入測試項標識存入需求標識符 完整源碼實現效果學…

Nginx學習與使用記錄

這里寫自定義目錄標題 定義域名&#xff08;本地&#xff09;Nginx的一下常用命令記錄win系統使用 .bat來啟動nginx配置 定義域名&#xff08;本地&#xff09; 本地定義域名不需要證書&#xff0c;直接更改hosts文件。 注意&#xff1a;在這個文件夾中是無法更改hosts文件的&…

Vue02-黑馬程序員學習筆記

一、今日學習目標 1.指令補充 指令修飾符v-bind對樣式增強的操作v-model應用于其他表單元素 2.computed計算屬性 基礎語法計算屬性vs方法計算屬性的完整寫法成績案例 3.watch偵聽器 基礎寫法完整寫法 4.綜合案例 &#xff08;演示&#xff09; 渲染 / 刪除 / 修改數量 …

一個簡約高級視差效果PR動態圖文開場視頻模板

這是一個高質量且易于定制的pr模板。具有模塊化結構&#xff0c;可以輕松更改內容。包括視頻教程&#xff0c;即使是新手小白也可以輕松套用模板制作視頻。 主要特點&#xff1a; 水平&#xff08;19201080&#xff09;和垂直&#xff08;10801920&#xff09;分辨率&#xff…

c語言:利用隨機函數產生20個[120, 834] 之間互不相等的隨機數, 并利用選擇排序法將其從小到大排序后輸出(每行輸出5個)

利用隨機函數產生20個[120, 834] 之間互不相等的隨機數&#xff0c; 并利用選擇排序法將其從小到大排序后輸出&#xff08;每行輸出5個&#xff09; 代碼如下&#xff1a; #include <stdio.h> #include <time.h> #include <stdlib.h> int shenchen(int a[…

三維模型相互轉換(obj文件轉inp文件)

三維模型文件根據其含義都是可以進行相互轉換的&#xff0c;這里主要介紹obj文件轉化為inp文件。 什么是inp文件&#xff1f; inp文件是以.inp為后綴的文本文件&#xff0c;它包括了模型的全部數據信息&#xff0c;ABAQUS求解器分析的對象是inp文件&#xff0c;軟件生成的.ca…

PHP身份證真偽驗證、身份證二、三要素核驗、身份證ocr接口

實名認證有利于網絡綠化&#xff0c;所以在互聯網發展迅速的今天&#xff0c;實名認證成了“剛需”。而OCR與實名認證兩種產品的結和更是擦出了美麗的火花。翔云人工智能開放平臺提供的實名認證OCR接口良好的展現出兩種功能結合的效果。以身份實名認證產品舉例來說&#xff0c;…

AI智能體|扣子Coze“圖像流”功能速覽

大家好&#xff0c;我是無界生長。 AI智能體&#xff5c;扣子Coze“圖像流”功能速覽Coze提供易上手的圖像處理工作流&#xff0c;包含智能生成、智能編輯和基礎編輯三類節點&#xff0c;旨在通過AI技術簡化圖像處理過程。本文對扣子Coze“圖像流”功能做了簡單介紹&#xff0…

【qt】初識模型和視圖

模型和視圖 一.模型和視圖的概念1.關系2.模型3.數據4.視圖5.特點 二.文件系統模型1.那種數據&#xff1f;2.界面拖放3.創建模型4.模型設置數據5.視圖設置模型6.模型索引7.模型操作數據①文件名②文件大小③文件類型④是否是目錄⑤文件路徑 三.字符串鏈表模型1.那種數據&#xf…

論Promise在前端江湖的地位及作用

系列文章&#xff1a; 先擼清楚&#xff1a;并發/并行、單線程/多線程、同步/異步 論Promise在前端江湖的地位及作用 前言 上篇文章闡述了并發/并行、單線程/多線程、同步/異步等概念&#xff0c;這篇將會分析Promise的江湖地位。 通過本篇文章&#xff0c;你將了解到&#x…

100base-tx、100base-fx的區別

100表示網線設計的頻率&#xff0c;單位MHz。值越大&#xff0c;網線的速度越快。baseBASEband的縮寫&#xff0c;基帶t物理介質是雙絞線纜f物理介質是光纖x同一個傳輸效率下的多種不同的標準 T表示雙絞線&#xff0c;base-tx是運行超五類雙絞線的快速以太網端口&#xff0c;全…

AI崛起,掌握它,開啟智能新生活!

AI崛起&#xff0c;掌握它&#xff0c;開啟智能新生活&#xff01; &#x1f604;生命不息&#xff0c;寫作不止 &#x1f525; 繼續踏上學習之路&#xff0c;學之分享筆記 &#x1f44a; 總有一天我也能像各位大佬一樣 &#x1f3c6; 博客首頁 怒放吧德德 To記錄領地 &…

Linux中vim的基本使用

目錄 vim中的三種模式以及基本操作命令模式(默認模式)插入模式底行模式 命令模式下的命令底行模式下的命令 vim是Linux和Unix環境下最基本的文本編輯器&#xff0c;類似于windows上的記事本 vim和Visual studio相比&#xff0c;vim并不集成&#xff0c;vim只能用來寫代碼 VS把寫…

Nginx限制IP訪問詳解

在Web服務器管理中&#xff0c;限制某些IP地址訪問網站是一個常見的需求。Nginx作為一款高性能的HTTP服務器和反向代理服務器&#xff0c;提供了靈活強大的配置選項來實現這一功能。本文將詳細講解如何在Nginx中限制IP訪問&#xff0c;并通過示例代碼展示具體操作。 一、Nginx…

使用 Python 簡單幾步去除 PDF 水印

推薦一個AI網站&#xff0c;免費使用豆包AI模型&#xff0c;快去白嫖&#x1f449;海鯨AI 在處理 PDF 文件時&#xff0c;水印有時會影響文件的可讀性或美觀性。幸運的是&#xff0c;Python 提供了多種庫來操作 PDF 文件&#xff0c;其中 PyMuPDF&#xff08;又名 fitz&#xf…

2024年5月24日 十二生肖 今日運勢

小運播報&#xff1a;2024年5月24日&#xff0c;星期五&#xff0c;農歷四月十七 &#xff08;甲辰年己巳月戊子日&#xff09;&#xff0c;法定工作日。 紅榜生肖&#xff1a;龍、牛、猴 需要注意&#xff1a;兔、羊、馬 喜神方位&#xff1a;東南方 財神方位&#xff1a;…

深度學習之基于Matlab的BP神經網絡交通標志識別

歡迎大家點贊、收藏、關注、評論啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代碼。 文章目錄 一項目簡介 二、功能三、系統四. 總結 一項目簡介 一、項目背景與意義 隨著智能交通系統&#xff08;ITS&#xff09;的快速發展&#xff0c;交通標志識別&#xff0…

BUUCTF---misc---[MRCTF2020]ezmisc

1、附件下載后是一張圖片 2、查看屬性&#xff0c;winhex分析&#xff0c;沒發現什么 3、在kali中binwalk和foremost也沒找到什么信息 4、用stegsolve分析也沒發現什么 5、這里幾乎常見的misc方法都試過了&#xff0c;還是沒有發現什么 6、回歸到圖片本身&#xff0c;想到的…