數據結構(13)堆

目錄

1、堆的概念與結構

2、堆的實現

2.1 向上調整算法(堆的插入)

2.2 向下調整算法(堆的刪除)?

?2.3 完整代碼

3、堆的應用

3.1 堆排序

3.2 Top-K問題


1、堆的概念與結構

堆是一種特殊的二叉樹,根結點最大的堆稱為大根堆(也叫最大堆),根結點最小的堆稱為小根堆(也叫最小堆)

堆具有以下性質:(1)堆中某個結點的值總是不大于或不小于其父結點的值

? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(2)堆總是一棵完全二叉樹

二叉樹的性質

對于具有n個結點的完全二叉樹,如果從上至下從左至右的數組順序對所有結點從0開始編號,對于序號為i的結點有:

1. 若 i > 0,i 位置的雙親結點序號:(i - 1)/ 2;i = 0,i 為根結點,無雙親結點

2. 若 2i + 1 < n,左孩子序號:2i + 1,若 2i + 1 >= n,則沒有左孩子

3. 若 2i + 1 < n,右孩子序號:2i + 2,若 2i + 2?>= n,則沒有右孩子

2、堆的實現

2.1 向上調整算法(堆的插入)

將新數據插入到數組的尾上,再進行向上調整算法,直到滿足堆。

向上調整算法

1、先將元素插入到堆的末尾,即最后一個孩子之后

2、插入之后如果堆的性質遭到破壞,將新插入節點順著其雙親往上調整到合適位置即可

void Swap(HPDataType* x, HPDataType* y)
{HPDataType tmp = *x;*x = *y;*y = tmp;
}void AdjustUp(HPDataType* arr, int child)
{int parent = (child - 1) / 2;while (child > 0){//大堆:         >//小堆:         <if (arr[child] < arr[parent]){//調整Swap(&arr[child], &arr[parent]);child = parent;parent = (parent - 1) / 2;}else{break;}}
}

2.2 向下調整算法(堆的刪除)?

?刪除堆是刪除堆頂的數據,將堆頂數據和最后一個數據交換,然后刪除最后一個數據,再進行向下調整算法。

向下調整算法

1、將堆頂元素與堆中最后一個元素進行交換

2、刪除堆中最后一個元素

3、將堆頂元素向下調整直到滿足堆的特性為止

void AdjustDown(HPDataType* arr, int parent, int n)
{int child = 2 * parent + 1;//左孩子while (child < n){if (child + 1 < n && arr[child] > arr[child + 1]){child = child + 1;}if (arr[child] < arr[parent]){//調整Swap(&arr[child], &arr[parent]);parent = child;child = 2 * child + 1;}else{break;}}
}void HPPop(HP* php)
{assert(!HPEmpty(php));//0   php->size - 1Swap(&php->arr[0], &php->arr[php->size - 1]);php->size--;//向下調整AdjustDown(php->arr, 0, php->size);
}

?2.3 完整代碼

Heap.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>//堆的結構
typedef int HPDataType;
typedef struct Heap
{HPDataType* arr;int size;     //有效數據個數int capacity; //空間大小
}HP;void HPInit(HP* php);
void HPDestroy(HP* php);
void HPPrint(HP* php);void HPPush(HP* php, HPDataType x);
void HPPop(HP* php);//判空
bool HPEmpty(HP* php);//取堆頂數據
HPDataType HPTop(HP* php);

Heap.c

#define  _CRT_SECURE_NO_WARNINGS 1
#include "Heap.h"void HPInit(HP* php)
{php->arr = NULL;php->size = php->capacity = 0;
}void HPDestroy(HP* php)
{if (php->arr)free(php->arr);php->arr = NULL;php->size = php->capacity = 0;
}void HPPrint(HP* php)
{for (int i = 0;i < php->size;i++){printf("%d ", php->arr[i]);}printf("\n");
}void Swap(HPDataType* x, HPDataType* y)
{HPDataType tmp = *x;*x = *y;*y = tmp;
}void AdjustUp(HPDataType* arr, int child)
{int parent = (child - 1) / 2;while (child > 0){//大堆:         >//小堆:         <if (arr[child] < arr[parent]){//調整Swap(&arr[child], &arr[parent]);child = parent;parent = (parent - 1) / 2;}else{break;}}
}void HPPush(HP* php, HPDataType x)
{assert(php);if (php->size == php->capacity){int newCapacity = php->capacity == 0 ? 4 : 2 * php->capacity;HPDataType* tmp = (HPDataType*)realloc(php->arr, newCapacity * sizeof(int));if (tmp == NULL){perror("realloc fail!");exit(1);}php->arr = tmp;php->capacity = newCapacity;}php->arr[php->size] = x;//向上調整AdjustUp(php->arr, php->size);php->size++;
}//判空
bool HPEmpty(HP* php)
{assert(php);return php->size == 0;
}void AdjustDown(HPDataType* arr, int parent, int n)
{int child = 2 * parent + 1;//左孩子while (child < n){if (child + 1 < n && arr[child] > arr[child + 1]){child = child + 1;}if (arr[child] < arr[parent]){//調整Swap(&arr[child], &arr[parent]);parent = child;child = 2 * child + 1;}else{break;}}
}void HPPop(HP* php)
{assert(!HPEmpty(php));//0   php->size - 1Swap(&php->arr[0], &php->arr[php->size - 1]);php->size--;//向下調整AdjustDown(php->arr, 0, php->size);
}//取堆頂數據
HPDataType HPTop(HP* php)
{assert(!HPEmpty(php));return php->arr[0];
}

test.c?

#define  _CRT_SECURE_NO_WARNINGS 1
#include "Heap.h"void test01()
{HP hp;HPInit(&hp);HPPush(&hp, 56);HPPush(&hp, 10);HPPush(&hp, 15);HPPush(&hp, 30);HPPush(&hp, 70);HPPush(&hp, 25);HPPrint(&hp);HPPop(&hp);HPPrint(&hp);HPDestroy(&hp);
}void test02()
{HP hp;HPInit(&hp);HPPush(&hp, 56);HPPush(&hp, 10);HPPush(&hp, 15);HPPush(&hp, 30);HPPrint(&hp);while (!HPEmpty(&hp)){int top = HPTop(&hp);printf("%d ", top);HPPop(&hp);}
}int main()
{//test01();test02();return 0;
}

3、堆的應用

3.1 堆排序

? ? ? ? 我們發現,依次取出堆頂元素,元素是按照從小到大(或從大到小)的順序排列輸出的,因此,我們可以使用堆這個數據結構來進行排序。

上面代碼的test02測試出來的結果如圖所示

版本一:基于已有數組建堆,取堆頂元素完成排序。

#define  _CRT_SECURE_NO_WARNINGS 1
#include "Heap.h"//堆排序
void HeapSort(int* arr, int n)
{HP hp;HPInit(&hp);for (int i = 0;i < n;i++){HPPush(&hp, arr[i]);}int i = 0;while (!HPEmpty(&hp)){int top = HPTop(&hp);arr[i++] = top;HPPop(&hp);}HPDestroy(&hp);
}int main()
{int arr[6] = { 19,15,20,17,13,10 };HeapSort(arr, 6);for (int i = 0;i < 6;i++){printf("%d ", arr[i]);}printf("\n");return 0;
}

該版本有一個前提,那就是必須要借助堆這個數據結構,而我們所說的堆排序,并不是要用對這個數據結構來排序,而是要借助堆的思想。

版本二:根據數組建堆,首尾交換,交換后的堆尾數據從堆中刪掉,將堆頂數據向下調整選出次大的數據。

第一步、根據數組進行建堆?

????????排升序——建大堆

????????排降序——建小堆

第二步、將堆頂和最后一個數據交換位置,--size并向下調整堆,重復該過程

void HeapSort(int* arr, int n)
{//建堆——向下調整算法建堆for (int i = (n - 1 - 1) / 2;i >= 0;i--){AdjustDown(arr, i, n);}//堆排序int end = n - 1;while (end > 0){Swap(&arr[0], &arr[end]);AdjustDown(arr, 0, end);end--;}
}

向下調整算法建堆時間復雜度為O(n)?

void HeapSort(int* arr, int n)
{//建堆——向上調整算法for (int i = 0;i < n;i++){AdjustUp(arr, i);}//堆排序int end = n - 1;while (end > 0){Swap(&arr[0], &arr[end]);AdjustDown(arr, 0, end);end--;}
}

向上調整算法建堆時間復雜度為O(nlogn)

3.2 Top-K問題

Top-K問題:求數據中前K個最大的元素或者最小的元素,一般情況下數據量都比較大。對于Top-K問題,能想到的對簡單直接的方式就是排序,最佳的方式就是使用堆排序,基本思路如下:

先取前K個數據建堆,遍歷剩下的n - K個數據和堆頂比較。找最大的前K個數據,建小堆,比堆頂數據大就和堆頂元素交換;找最小的前K個數據,建大堆,比堆頂數據小就和堆頂元素交換。

#include "Heap.h"void CreateNData()
{//造數據int n = 100000;srand(time(0));const char* file = "data.txt";FILE* fin = fopen(file, "w");if (fin == NULL){perror("fopen error");return;}for (int i = 0;i < n;i++){int x = (rand() + i) % 100000;fprintf(fin, "%d\n", x);}fclose(fin);
}void TopK()
{printf("請輸入k:");int k = 0;scanf("%d", &k);const char* file = "data.txt";FILE* fout = fopen(file, "r");if (fout == NULL){perror("fopen fail");return;}//找最大的前k個數據,建小堆int* minHeap = (int*)malloc(k * sizeof(int));if (minHeap == NULL){perror("malloc fail");return;}for (int i = 0;i < k;i++){fscanf(fout, "%d", &minHeap[i]);}//minHeap--向下調整建堆for (int i = (k - 1 - 1) / 2;i >= 0;i--){AdjustDown(minHeap, i, k);}//遍歷剩下的n-k個數據,跟堆頂比較int x = 0;while (fscanf(fout, "%d", &x) != EOF){//minHeap-top    x if (minHeap[0] < x){minHeap[0] = x;AdjustDown(minHeap, 0, k);}}for (int i = 0;i < k;i++){printf("%d ", minHeap[i]);}fclose(fout);
}int main()
{//CreateNData();TopK();return 0;
}

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

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

相關文章

C++模板知識點3『std::initializer_list初始化時逗號表達式的執行順序』

std::initializer_list初始化時逗號表達式的執行順序 在使用Qt Creator4.12.2&#xff0c;Qt5.12.9 MinGW開發的過程中發現了一個奇怪的現象&#xff0c;std::initializer_list<int>在初始化構造時的執行順序反了&#xff0c;經過一番測試發現&#xff0c;其執行順序可正…

【Unity3D】Shader圓形弧度裁剪

片元著色器&#xff1a; float3 _Center float3(0, 0, 0); float3 modelPos i.modelPos;// float angle atan2(modelPos.y - _Center.y, modelPos.x - _Center.x); // 計算角度&#xff0c;范圍-π到π float angle atan2(modelPos.y - _Center.y, modelPos.z - _Center.z)…

curl發送文件bodyParser無法獲取請求體的問題分析

問題及現象 開發過程使用curlPUT方式發送少量數據, 后端使用NodeJSexpress框架bodyParser,但測試發現無法獲取到請求體內容,現象表現為req.body 為空對象 {} 代碼如下: const bodyParser require(body-parser); router.use(/api/1, bodyParser.raw({limit: 10mb, type: */*}))…

Vue3 學習教程,從入門到精通,Vue 3 內置屬性語法知識點及案例代碼(25)

Vue 3 內置屬性語法知識點及案例代碼 Vue 3 提供了豐富的內置屬性&#xff0c;幫助開發者高效地構建用戶界面。以下將詳細介紹 Vue 3 的主要內置屬性&#xff0c;并結合詳細的案例代碼進行說明。每個案例代碼都包含詳細的注釋&#xff0c;幫助初學者更好地理解其用法。1. data …

機器學習基石:深入解析線性回歸

線性回歸是機器學習中最基礎、最核心的算法之一&#xff0c;它為我們理解更復雜的模型奠定了基礎。本文將帶你全面解析線性回歸的方方面面。1. 什么是回歸&#xff1f; 回歸分析用于預測連續型數值。它研究自變量&#xff08;特征&#xff09;與因變量&#xff08;目標&#xf…

OneCodeServer 架構深度解析:從組件設計到運行時機制

一、架構概覽與設計哲學1.1 系統定位與核心價值OneCodeServer 作為 OneCode 平臺的核心服務端組件&#xff0c;是連接前端設計器與后端業務邏輯的橋梁&#xff0c;提供了從元數據定義到應用程序執行的完整解決方案。它不僅是一個代碼生成引擎&#xff0c;更是一個全生命周期管理…

Jwts用于創建和驗證 ??JSON Web Token(JWT)?? 的開源庫詳解

Jwts用于創建和驗證 ??JSON Web Token&#xff08;JWT&#xff09;?? 的開源庫詳解在 Java 開發中&#xff0c;提到 Jwts 通常指的是 ??JJWT&#xff08;Java JWT&#xff09;庫??中的核心工具類 io.jsonwebtoken.Jwts。JJWT 是一個專門用于創建和驗證 ??JSON Web To…

如果發送的數據和接受的數據不一致時,怎么辦?

那ART4222這個板卡舉例&#xff0c;我之間輸入一個原始數據“6C532A14”&#xff0c;但是在選擇偶校驗時&#xff0c;接收的是“6C532B14”&#xff0c;我發送的碼率&#xff08;運行速度&#xff09;是100000&#xff0c;但接受的不穩定&#xff0c;比如&#xff1b;“100100.…

ISCC認證:可持續生產的新標桿。ISCC如何更快認證

在全球可持續發展浪潮中&#xff0c;ISCC&#xff08;國際可持續與碳認證&#xff09;體系已成為企業綠色轉型的重要工具。這一國際公認的認證系統覆蓋農業、林業、廢棄物處理等多個領域&#xff0c;通過嚴格的可持續性標準、供應鏈可追溯性要求和碳排放計算規范&#xff0c;建…

想對學習自動化測試的一些建議

Python接口自動化測試零基礎入門到精通&#xff08;2025最新版&#xff09;接觸了不少同行&#xff0c;由于他們之前一直做手工測試&#xff0c;現在很迫切希望做自動化測試&#xff0c;其中不乏工作5年以上的人。 本人從事軟件自動化測試已經近5年&#xff0c;從server端到web…

電子電氣架構 ---智能電動汽車嵌入式軟件開發過程中的block點

我是穿拖鞋的漢子,魔都中堅持長期主義的汽車電子工程師。 老規矩,分享一段喜歡的文字,避免自己成為高知識低文化的工程師: 做到欲望極簡,了解自己的真實欲望,不受外在潮流的影響,不盲從,不跟風。把自己的精力全部用在自己。一是去掉多余,凡事找規律,基礎是誠信;二是…

createAsyncThunk

下面&#xff0c;我們來系統的梳理關于 Redux Toolkit 異步操作&#xff1a;createAsyncThunk 的基本知識點&#xff1a;一、createAsyncThunk 概述 1.1 為什么需要 createAsyncThunk 在 Redux 中處理異步操作&#xff08;如 API 調用&#xff09;時&#xff0c;傳統方法需要手…

STM32F103C8T6 BC20模塊NBIOT GPS北斗模塊采集溫濕度和經緯度發送到EMQX

云平臺配置 訪問下載頁面&#xff1a;免費試用 EMQX Cloud 或 EMQX Enterprise | 下載 EMQX&#xff0c;根據需求選擇對應版本下載。將下載的壓縮包上傳至服務器&#xff08;推薦存放于C盤根目錄&#xff0c;便于后續操作&#xff09;&#xff0c;并解壓至指定路徑&#xff08…

YOLO11漲點優化:自研檢測頭, 新創新點(SC_C_11Detect)檢測頭結構創新,實現有效漲點

目標檢測領域迎來重大突破!本文揭秘原創SC_C_11Detect檢測頭,通過空間-通道協同優化與11層深度結構,在YOLO系列上實現mAP最高提升5.7%,小目標檢測精度暴漲9.3%!創新性結構設計+即插即用特性,為工業檢測、自動駕駛等場景帶來革命性提升! 一、傳統檢測頭的三大痛點 在目…

OSCP 考試期間最新考試政策

根據 Offensive Security 官方最新考試政策&#xff08;2025 年 7 月&#xff09;&#xff0c;OSCP 考試期間禁止或嚴格限制以下工具與行為&#xff1a; 一、絕對禁止使用的工具/服務 類別舉例說明商業/付費版本Metasploit Pro、Burp Suite Pro、Cobalt Strike、Canvas、Core …

如何基于MQ實現分布式事務

文章目錄1.可靠消息最終一致性1.1 本地消息表1.1.1 本地消息表的優缺點1.消息堆積&#xff0c;掃表慢2.集中式掃表&#xff0c;會影響正常業務3.定時掃表的延遲問題1.1.2 本地消息表的代碼實踐1.表結構設計2.具體業務實現1.2 事務消息1.2.1 事務消息的三個階段階段1&#xff1a…

ARM學習(45)AXI協議總線學習

筆者來介紹一下ARM AMBA 總線中的AXI協議 1、簡介 ARM 公司推出的AMBA 總線(Advanced Microcontroller Bus Architecture) ,目前已經推出到AMBA5版本。主要包括 APB:Advanced Peripheral Bus,針對外設 AHB:Advanced High-Performance Bus,高性能總線,支持64/128 位多管…

Visual C++與HGE游戲引擎:創建偽2.5D斜45度視角游戲

本文還有配套的精品資源&#xff0c;點擊獲取 簡介&#xff1a;本教程專注講解如何結合Visual C和HGE游戲引擎構建一個斜45度視角的偽2.5D游戲世界。HGE提供了DirectX的接口&#xff0c;簡化了圖形和音頻處理&#xff0c;使得開發者可以專注于游戲邏輯和視覺效果的實現。教程…

打造個人數字圖書館:LeaNote+cpolar如何成為你的私有化知識中樞?

文章目錄前言1. 安裝Docker2. Docker本地部署Leanote螞蟻筆記3. 安裝cpolar內網穿透4. 固定Leanote螞蟻筆記公網地址前言 在信息爆炸的時代&#xff0c;如何系統管理知識資產并實現價值輸出&#xff1f;螞蟻筆記&#xff08;Leanote&#xff09;提供了一種全新解決方案。這款開…

[特殊字符]? 整個鍵盤控制無人機系統框架

&#x1f3af; 五大核心模塊詳解1. &#x1f4e5; 輸入處理模塊keyboard_control_node ├── 功能&#xff1a;捕獲鍵盤輸入并轉換為ROS消息 ├── 文件&#xff1a;keyboard_control.cpp ├── 輸入&#xff1a;鍵盤按鍵 (W/A/S/D/R/F/Q/E/L/ESC) ├── 輸出&#xff1a;g…