堆的實現(C語言版)

在這里插入圖片描述

文章目錄

  • 概述
  • 堆的實現
    • 初始化
    • 銷毀
    • 插入
    • 刪除
    • 取堆頂元素
    • 求堆的長度
    • 判斷堆是否為空
  • 完整代碼

概述

如果有一個關鍵碼的集合K = {k0,k1,k2…kn-1},把它的所有元素按完全二叉樹的順序存儲方式存儲在一個一維數組中,并滿足:Ki <=K2*i+1 且 Ki<=K2*i+2 (Ki >= K2*i+1且 Ki>= K2*i+1) i = 0,1,2…,則稱為小堆(或大堆)。將根節點最大的堆叫做最大堆或大根堆,根節點最小的堆叫做最小堆或小根堆。堆的性質:

  • 堆中某個節點的值總是不大于或不小于其父節點的值;
  • 堆總是一棵完全二叉樹

在這里插入圖片描述

堆的實現

初始化

堆的存儲結構是一個數組,堆的初始化需要定義一個數組,當前元素個數和容量。和順序表的初始化一樣。

typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;void HeapInit(HP* php)
{assert(php);php->a = NULL;php->size = php->capacity = 0;
}

銷毀

釋放數組a的空間,將php->capacity = php->size = 0

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

插入

堆的插入是先在數組的最后插入元素,但是需要滿足堆的特點(大堆或小堆),因此需要用到向上調整算法,來實現這一特點。

介紹向上調整算法

這里小編以實現小堆為例

在數組的最后插入一個元素child,然后這個元素與其雙親節點parent進行比較:

  • 如果 child>parent:滿足小堆的條件,無需交換
  • 如果 child<parent:不滿足小堆條件,此時需要將孩子節點child與它的雙親結點parent進行交換,此時原來的雙親結點parent變成了孩子結點child,原來的孩子節點child變成了雙親結點parent。此時,再讓現在的雙親結點parent和它的雙親結點parent進行比較,如果不滿足小堆,則繼續交換,繼續比較
  • 循環結束的條件是child>0

舉個例子:

如下,在堆中插入元素10:

在這里插入圖片描述
將10與它的雙親結點進行比較,10<28,不滿足小堆的條件,將10和28,進行交換:

在這里插入圖片描述

交換完后,此時的10變成了28的雙親結點,28變成了10的孩子結點。現在再將10與它的雙親結點比較,10<18,不滿足小堆的特點,繼續交換。

在這里插入圖片描述

交換完后10變成了18的雙親結點,18變成了10的孩子結點。10和它的雙親結點比較,依然不滿足小堆條件,繼續交換

在這里插入圖片描述

此時,10已經變成了根節點,并且滿足小堆的條件,循環結束。

看了圖解,對向上調整算法有了大概的印象,但是代碼的編寫,還需要再去分析一下。

定義parent是孩子的雙親結點,雙親結點parent與孩子結點child滿足parent = (child - 1) / 2關系。進入循環,比較孩子節點的值和雙親結點的值,判斷是否滿足小堆的條件。

void swap(HPDataType* p1, HPDataType* p2)
{int 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 = (parent - 1) / 2;}else{break;}}
}

寫完向上調整算法,便可實現插入操作

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");exit(-1);}php->a = tmp;php->capacity = newCapacity;}php->a[php->size] = x;php->size++;AdjustUp(php->a, php->size - 1);
}

刪除

在刪除操作里面,一般規定刪除堆頂,即根節點

在這里插入圖片描述

刪除根節點的常規操作是將根結點和最后一個葉節點進行交換,然后尾刪即可,此時根節點的左右子樹依然是小堆

在這里插入圖片描述
但是根節點不滿足小隊的條件,因此引入向下調整算法

向下調整算法:

向上調整算法是一個道理

但是此時根節點是雙親結點,有兩個孩子,不知道該選擇哪一個孩子。這里使用到了假設法:假設左孩子小,如果假設錯了,更新一下

判斷雙親結點和孩子結點的大小:

  • 如果雙親結點小于孩子結點,直接結束
  • 如果雙親結點大于孩子結點,交換雙親結點和孩子結點的值,然后更新一下雙親結點的位置和孩子節點的位置

循環結束的條件是child<size

和向上調整算法基本一致,直接上代碼:

AdjustDown(HPDataType* a,int size, int parent)
{int child = parent * 2 + 1;while (child < size){if (a[child] > a[child + 1] && child + 1 < size){child++;}if (a[child] < a[parent]){swap(a[parent], a[child]);parent = child;child = child * 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;
}

判斷堆是否為空

先判斷堆是否存在,如果php->size==0,那么堆為空,返回true,反之返回false

bool HeapEmpty(HP* php)
{assert(php);return php->size == 0;
}

完整代碼

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 HeapDestroy(HP* php);
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

# define _CRT_SECURE_NO_WARNINGS#include"Heap.h"void HeapInit(HP* php)
{assert(php);php->a = NULL;php->size = php->capacity = 0;
}void HeapDestroy(HP* php)
{assert(php);free(php->a);php->capacity = php->size = 0;
}void swap(HPDataType* p1, HPDataType* p2)
{int 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 = (parent - 1) / 2;}else{break;}}
}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");exit(-1);}php->a = tmp;php->capacity = newCapacity;}php->a[php->size] = x;php->size++;AdjustUp(php->a, php->size - 1);
}AdjustDown(HPDataType* a,int size, int parent)
{int child = parent * 2 + 1;while (child < size){if (a[child] > a[child + 1] && child + 1 < size){child++;}if (a[child] < a[parent]){swap(a[parent], a[child]);parent = child;child = child * 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;
}

在這里插入圖片描述

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

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

相關文章

Python Opencv實踐 - 全景圖片拼接stitcher

做一個全景圖片切片的程序Spliter 由于手里沒有切割好的全景圖片資源&#xff0c;因此首先寫了一個切片的程序spliter。 如果有現成的切割好的待拼接的切片文件&#xff0c;則不需要使用spliter。 對于全景圖片的拼接&#xff0c;需要注意一點&#xff0c;各個切片圖片之間要有…

NX二次開發UF_CSYS_map_point 函數介紹

文章作者&#xff1a;里海 來源網站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CSYS_map_point Defined in: uf_csys.h int UF_CSYS_map_point(int input_csys, double input_point [ 3 ] , int output_csys, double output_point [ 3 ] ) overview 概述 Ma…

Android11編譯第七彈:串口文件讀寫

問題&#xff1a;需要對SIM卡進行管理&#xff0c;支持APP切換SIM卡。此功能需要訪問串口文件&#xff0c;并且對串口文件進行讀寫。APP操作串口文件/dev/ttyUSB1時&#xff0c;串口文件打開失敗。 2023-11-23 10:59:44.092 14264-14264 MULTI_CARD_SerialHandle com.wellnkio…

三分鐘快速理解 ChatGPT 背后的大模型技術

在過去的十年中&#xff0c;人工智能領域取得了重大突破&#xff0c;其中自然語言處理&#xff08;NLP&#xff09;是其重要子領域之一。NLP使用的模型之一是大型語言模型&#xff08;LLMs&#xff09;。LLMs被設計用于處理大量文本數據&#xff0c;采用先進的神經網絡架構&…

nodejs 文件目錄監聽 chokidar watchpack

文件監聽實現&#xff0c;推薦使用chokidar&#xff1a; chokidar 默認是基于事件監聽文件 const chokidar require("chokidar"); const folderToWatch path.join(__dirname, "lib"); const watcher chokidar.watch(folderToWatch, { ignored: /(^|[…

在Vue中使用Echarts

文章目錄 Echarts1. 介紹2. 體驗NPM 安裝 Echarts定義 Echarts 容器引入 Echarts 3. 基礎配置 Echarts 1. 介紹 常見的數據可視化庫&#xff1a; D3.js 目前 Web 端評價最高的 Javascript 可視化工具庫(入手難)ECharts.js 百度出品的一個開源 Javascript 數據可視化庫Highch…

鼠標拖拽問題,不選中文本不觸發單擊事件

文章目錄 1. 為什么鼠標單擊的時候觸發了mousemove事件&#xff1f;明明鼠標沒有移動2. 鼠標拖拽元素怎么能不觸發單擊事件&#xff1f;怎么處理鼠標在元素內的相對定位&#xff0c;而不是每次定位到左上角&#xff1f;方式一&#xff1a;拖拽的元素沒有注冊click監聽就不會觸發…

10年測試老鳥,自動化測試經驗10條建議,一路狂飆...

目錄&#xff1a;導讀 前言一、Python編程入門到精通二、接口自動化項目實戰三、Web自動化項目實戰四、App自動化項目實戰五、一線大廠簡歷六、測試開發DevOps體系七、常用自動化測試工具八、JMeter性能測試九、總結&#xff08;尾部小驚喜&#xff09; 前言 1、哪一刻&#x…

Java面試題(每天10題)-------連載(37)

目錄 Mysql篇 1、Mysql如何優化DISTINCT&#xff1f; 2、如何輸入字符為十六進制數字&#xff1f; 3、如何顯示前50行&#xff1f; 4、可以使用多少列創建索引&#xff1f; 5、NOW()和CURRENT_DATE()有什么區別&#xff1f; 6、什么樣的對象可以使用CREATE語句創建&…

Postman如何使用(二):Postman Collection的創建/使用/導出分享等

一、什么是Postman Collection&#xff1f; Postman Collection是可讓您將各個請求分組在一起。 您可以將這些請求組織到文件夾中。中文經常將collection翻譯成收藏夾。如果再下文中看到這樣的翻譯不要覺得意外。Postman Collection會使你的工作效率更上一層樓。Postman Colle…

【洛谷 B2080】計算多項式的值 題解(順序結構+四則運算)

計算多項式的值 題目描述 假定多項式的形式為 x n x ( n ? 1 ) x^nx^{(n-1)} xnx(n?1) … x 2 x 1 x^2x1 x2x1&#xff0c;請計算給定單精度浮點數 x x x 和正整數 n n n 值的情況下這個多項式的值。多項式的值精確到小數點后兩位&#xff0c;保證最終結果在 doub…

NFS 速度變慢問題排查 性能優化

NFS 使用 RPC 來進行客戶端和服務器之間的通信。而在 RPC 的底層&#xff0c;NFS 使用 TCP 來進行數據的可靠傳輸&#xff0c;以便客戶端和服務器之間能夠有效地傳輸文件和進行遠程調用&#xff08;默認為TCP,也可調整為udp&#xff09; 1.首先服務器端啟動RPC服務portmap&…

教師工作就業前景

在這個知識爆炸的時代&#xff0c;當老師無疑是社會發展的重要基石。隨著科技的進步和社會的發展&#xff0c;教育行業的需求也在不斷增長。那么&#xff0c;教師工作的就業前景如何呢&#xff1f; 我們來看看教師工作的市場需求。隨著國家對教育的重視和投入的增加&#xff0c…

C/C++ 實現Socket交互式服務端

在 Windows 操作系統中&#xff0c;原生提供了強大的網絡編程支持&#xff0c;允許開發者使用 Socket API 進行網絡通信&#xff0c;通過 Socket API&#xff0c;開發者可以創建、連接、發送和接收數據&#xff0c;實現網絡通信。本文將深入探討如何通過調用原生網絡 API 實現同…

「Java開發中文指南」IntelliJ IDEA插件安裝(一)

IntelliJ IDEA是java編程語言開發的集成環境。IntelliJ在業界被公認為最好的Java開發工具&#xff0c;尤其在智能代碼助手、代碼自動提示、重構、JavaEE支持、各類版本工具(git、svn等)、JUnit、CVS整合、代碼分析、 創新的GUI設計等方面的功能是非常強大的。 插件擴展了Intel…

【分布式】分布式中的時鐘

一、物理時鐘 vs 邏輯時鐘 時鐘的存在主要是為了標識事件的發生順序。 分布式系統不使用物理時鐘記錄事件&#xff0c;分布式系統中每個節點記錄的時間并不一樣&#xff0c;即使設置了 NTP 時間同步節點間也存在毫秒級別的偏差 所以需要有另外的方法記錄事件順序關系&#x…

vue2中使用echarts

1,安裝echarts npm install --save echarts 2&#xff0c;具體頁面 <template><div class"app-container"><div class"aa" id"main" style"width: 500px; height: 400px;"></div></div> </te…

PDF 批量處理軟件BatchOutput PDF mac中文版介紹

BatchOutput PDF mac是一款適用于 Mac 的 PDF 批量處理軟件。它可以幫助用戶將多個 PDF 文件進行異步處理&#xff0c;提高工作效率。 BatchOutput PDF 可以自動化執行許多任務&#xff0c;包括 PDF 文件的打印、轉換、分割、壓縮、加密、重命名等&#xff0c;而且它還可以將自…

Elasticsearch知識

目錄 Elasticsearch邏輯設計和物理設計 邏輯設計物理設計Elasticsearch原理 倒排索引文檔的分析過程保存文檔搜索文檔寫數據的底層原理 數據刷新&#xff08;fresh&#xff09;事務日志的寫入ES在大數據量下的性能優化 文件系統緩存優化數據預熱文檔&#xff08;Document&…

【數據分享】2023年我國省市縣三級的瞪羚企業數量(免費獲取/Excel/Shp格式)

企業是經濟活動的參與主體。一個城市的企業數量決定了這個城市的經濟發展水平&#xff01;比如一個城市的金融企業較多&#xff0c;那這個城市的金融產業肯定比較發達&#xff1b;一個城市的制造業企業較多&#xff0c;那這個城市的制造業肯定比較發達。 之前我們給大家分享了…