【數據結構與算法】——堆(補充)

前言

上一篇文章講解了堆的概念和堆排序,本文是對堆的內容補充
主要包括:堆排序的時間復雜度、TOP

這里寫目錄標題

    • 前言
    • 正文
      • 堆排序的時間復雜度
      • TOP-K

正文

堆排序的時間復雜度

前文提到,利用堆的思想完成的堆排序的代碼如下(包含向下調整):

#include <stdio.h>// 交換兩個整數的值
void Swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}// 大頂堆向下調整
void AdjustDown(int* arr, int parent, int n)
{int child = parent * 2 + 1; // 左孩子while (child < n){// 保障右孩子存在且右孩子更大if (child + 1 < n && arr[child] < arr[child + 1]){child++;}if (arr[child] > arr[parent]){// 調整Swap(&arr[child], &arr[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}// 堆排序
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--;}
}// 打印數組
void PrintArray(int* arr, int n)
{for (int i = 0; i < n; i++){printf("%d ", arr[i]);}printf("\n");
}int main()
{int arr[] = { 4, 1, 3, 2, 16, 9, 10, 14, 8, 7 };int n = sizeof(arr) / sizeof(arr[0]);printf("排序前的數組: ");PrintArray(arr, n);HeapSort(arr, n);printf("排序后的數組: ");PrintArray(arr, n);return 0;
}

那么我們如何計算他的時間復雜度呢?
1.建堆過程
堆排序的算法中,首先先是向下調整算法
在這里插入圖片描述
需要移動結點總的移動步數為:每層結點個數*向下調整次數
列式為:
在這里插入圖片描述
很明顯,這是高中學過的等比數列,利用錯位相減法可以算出T(n)
結果是:
在這里插入圖片描述

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

同樣我們可以算出向上排序的時間復雜度為:

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

堆排序的時間復雜度為 O(n log n),以下是具體分析:

排序階段
每次將堆頂元素(最大值)與堆尾元素交換,然后對剩余 (n-1, n-2, \dots, 1) 個元素重新調整堆。每次調整堆的時間為 (O(log n))(堆的高度為 (log n)),共進行 (n-1) 次交換和調整,總時間為
在這里插入圖片描述
最后匯總
建堆階段 (O(n)) 和排序階段 (O(n \log n)) 中,(O(n \log n)) 是主導項,因此堆排序的總時間復雜度為 (O(n log n))

TOP-K

TOP-K問題:即求數據結合中前K個最?的元素或者最?的元素,?般情況下數據量都?較?。
比如崩壞 星穹鐵道活躍度最高的240萬個玩家(這只是例子)
對于Top-K問題,能想到的最簡單直接的?式就是排序,但是:如果數據量?常?,排序就不太可取了
(可能數據都不能?下?全部加載到內存中)。最佳的?式就是?堆來解決,基本思路如下:

1)?數據集合中前K個元素來建堆
前k個最?的元素,則建?堆
前k個最?的元素,則建?堆
2)?剩余的N-K個元素依次與堆頂元素來?較,不滿?則替換堆頂元素
將剩余N-K個元素依次與堆頂元素?完之后,堆中剩余的K個元素就是所求的前K個最?或者最?的元素

代碼如下
1.先把前面學過的代碼拿過來,這里剛好可以復習一下如何用向下調整法建堆

//求最大k個數
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>//堆的結構
typedef int HPDataType;
typedef struct Heap
{HPDataType* arr;int size;    //有效數據個數int capacity;//空間大小
}HP;void Swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}
void AdjustDown(HPDataType* arr, int parent, int n)
{int child = parent * 2 + 1;//左孩子while (child < n){//保障右孩子if (child + 1 < n && arr[child] < arr[child + 1]){child++;}if (arr[child] > arr[parent]){//調整Swap(&arr[child], &arr[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}

2.這里沒有數據,我們先創造100000個隨機數

void CreatNdata()
{//造數據int n = 100000;srand(time(0));const char* file = "data.txt";FILE* fin = fopen(file, "w");if (fin == NULL){perror("fopen fail!");return;}for (int i = 0; i < n; i++){int x = (rand() + 1) % n;fprintf(fin, "%d\n", x);}fclose(fin);
}

并且建立“data.txt”文本文件存放,,該文件位置與代碼位置一致,打開方法為
右擊文件名
在這里插入圖片描述
點這個
在這里插入圖片描述

就可以看到這個文件了,選擇記事本打開
在這里插入圖片描述

3.具體寫法
1) 輸入k值
2)以只讀的形式打開文件
3)動態分布一個大小為k的數組
4)先讀到k個數據并存到minheap[]

  • 運用 fscanf 函數從文件中讀取前 k 個整數,并將它們存儲到 minheap 數組里。
  • 從最后一個非葉子節點開始,通過AdjustDown函數對這 k 個數據進行調整,構建一個最小堆。
    5)讀取剩余元素并更新最小堆
  • 利用 while 循環持續從文件中讀取剩余的數據,直到文件結束(EOF 表示文件結束)。
  • 對于每個讀取到的數 x,若它比堆頂元素 minheap[0] 大,就把堆頂元素替換為 x,接著調用 AdjustDown 函數重新調整堆,保證堆仍然是最小堆。

6)關閉文件

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 error");return;}int val = 0;int* minheap = (int*)malloc(sizeof(int) * k);if (minheap == NULL){perror("malloc fail");return;}for (int i = 0; i < k; i++){fscanf(fout, "%d", &minheap[i]);}//建立k個數據的小堆for (int i = (k - 1 - 1) / 2; i >= 0; i--){AdjustDown(minheap, i, k);}int x = 0;while (fscanf(fout, "%d", &x) != EOF){//讀取剩余的數據,誰比堆頂大,就替換它進堆if (x > minheap[0]){minheap[0] = x;AdjustDown(minheap, 0, k);}}for (int i = 0; i < k; i++){printf("%d ", minheap[i]);}printf("\n");fclose(fout);
}int main()
{CreatNdata();topk();return 0;
}

最小值代碼

//求最小幾個數
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>// 堆的結構
typedef int HPDataType;
typedef struct Heap
{HPDataType* arr;int size;    // 有效數據個數int capacity; // 空間大小
}HP;// 交換兩個整數的值
void Swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}// 大頂堆向下調整
void AdjustDown(HPDataType* arr, int parent, int n)
{int child = parent * 2 + 1; // 左孩子while (child < n){// 保障右孩子存在且右孩子更大if (child + 1 < n && arr[child] < arr[child + 1]){child++;}if (arr[child] > arr[parent]){// 調整Swap(&arr[child], &arr[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}// 生成隨機數據并保存到文件
void CreatNdata()
{// 造數據int n = 100000;srand(time(0));const char* file = "data.txt";FILE* fin = fopen(file, "w");if (fin == NULL){perror("fopen fail!");return;}for (int i = 0; i < n; i++){int x = (rand() + 1) % n;fprintf(fin, "%d\n", x);}fclose(fin);
}// 找出最小的k個數
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 error");return;}int val = 0;int* maxheap = (int*)malloc(sizeof(int) * k);if (maxheap == NULL){perror("malloc fail");return;}// 讀取前k個數據for (int i = 0; i < k; i++){fscanf(fout, "%d", &maxheap[i]);}// 建立k個數據的大頂堆for (int i = (k - 1 - 1) / 2; i >= 0; i--){AdjustDown(maxheap, i, k);}int x = 0;//修改后while (fscanf(fout, "%d", &x) != EOF){// 讀取剩余的數據,誰比堆頂小,就替換它進堆if (x < maxheap[0]){maxheap[0] = x;AdjustDown(maxheap, 0, k);}}// 輸出最小的k個數for (int i = 0; i < k; i++){printf("%d ", maxheap[i]);}printf("\n");fclose(fout);free(maxheap);
}int main()
{CreatNdata();topk();return 0;
}

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

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

相關文章

什么是柜臺債

柜臺債&#xff08;柜臺債券業務&#xff09;是指通過銀行等金融機構的營業網點或電子渠道&#xff0c;為投資者提供債券買賣、托管、結算等服務的業務模式。它允許個人、企業及機構投資者直接參與銀行間債券市場的交易&#xff0c;打破了以往僅限機構參與的壁壘。以下是綜合多…

【Android讀書筆記】讀書筆記記錄

文章目錄 一. Android開發藝術探索1. Activity的生命周期和啟動模式1.1 生命周期全面分析 一. Android開發藝術探索 1. Activity的生命周期和啟動模式 1.1 生命周期全面分析 onPause和onStop onPause后會快速調用onStop&#xff0c;極端條件下直接調用onResume 當用戶打開新…

Java對象內存結構詳解

Java對象內存結構詳解 Java對象在JVM內存中的存儲結構可以分為三個部分&#xff1a;對象頭&#xff08;Header&#xff09;、實例數據&#xff08;Instance Data&#xff09;和對齊填充&#xff08;Padding&#xff09;。以下是64位JVM&#xff08;開啟壓縮指針&#xff09;下…

【TI MSPM0】Printf重定向學習

一、新建工程 通過XDS110與電腦進行通信。 選擇這兩個引腳 需要添加這兩個頭文件 在程序中添加這三個函數即可對printf進行重定向 二、封裝函數 另一種方法 封裝一個函數&#xff0c;定義一個數組

深度強化學習基礎 0:通用學習方法

過去自己學習深度強化學習的痛點&#xff1a; 只能看到各種術語、數學公式勉強看懂&#xff0c;沒有建立清晰且準確關聯 多變量交互關系浮于表面&#xff0c;有時候連環境、代理控制的變量都混淆 模型種類繁多&#xff0c;概念繁雜難整合、對比或復用&#xff0c;無框架分析所…

asm匯編源代碼之-字庫轉換程序

將標準的16x16點陣漢字庫(下載16x16漢字庫)轉換成適合VGA文本模式下顯示的點陣漢字庫 本程序需要調用file.asm中的子程序,所以連接時需要把file連接進來,如下 C:\> tlink chghzk file 調用參數描述如下 C:\> chghzk ; 無調用參數,轉換標準庫文件(SRC16.FNT)為適合VGA…

uniapp轉換markdown

效果 AI智能體 微信小程序 流式 1.安裝Node.js 參考:2024最新版Node.js下載安裝及環境配置教程&#xff08;非常詳細&#xff09;_node.js 安裝-CSDN博客 2.需要克隆項目到本地或直接到項目地址下載壓縮包。 參考&#xff1a;uniapp中解析markdown支持網頁和小程序_uniapp ma…

用java代碼如何存取數據庫的blob字段

一.業務 在業務中我們被要求將文件或圖片等轉成 byte[] 或 InputStream存到數據庫的Blob類型的字段中. 二.Blob類型介紹 在 MySQL 中&#xff0c;Blob 數據類型用于存儲二進制數據。MySQL 提供了四種不同的 Blob 類型&#xff1a; TINYBLOB: 最大存儲長度為 255 個字節。BL…

qemu(2) -- 定制開發板

1. 前言 qemu支持自定義開發板&#xff0c;本文就記錄一下折騰的過程。基于qemu-10.0.0-rc3添加x210vb3s開發板。 2. 添加板卡文件 網上參考了一些文章&#xff0c;有些文章使用的版本和我的不一樣&#xff0c;折騰起來費了點時間&#xff0c;最后發現還是直接參考qemu中已有…

Python在糖尿病分類問題上尋找具有最佳 ROC AUC 分數和 PR AUC 分數(決策樹、邏輯回歸、KNN、SVM)

Python在糖尿病分類問題上尋找具有最佳 ROC AUC 分數和 PR AUC 分數&#xff08;決策樹、邏輯回歸、KNN、SVM&#xff09; 問題模板解題思路1. 導入必要的庫2. 加載數據3. 劃分訓練集和測試集4. 數據預處理5. 定義算法及其參數6. 存儲算法和對應指標7. 訓練模型并計算指標8. 找…

CPU(中央處理器)

一、CPU的定義與核心作用 CPU 是計算機的核心部件&#xff0c;負責 解釋并執行指令、協調各硬件資源 以及 完成數據處理&#xff0c;其性能直接影響計算機的整體效率。 核心功能&#xff1a; 從內存中讀取指令并譯碼。執行算術邏輯運算。控制數據在寄存器、內存和I/O設備間的…

上層 Makefile 控制下層 Makefile 的方法

在復雜的項目中&#xff0c;通常會將項目劃分為多個模塊或子項目&#xff0c;每個模塊都有自己的 Makefile。上層 Makefile 的作用是協調和控制這些下層 Makefile 的構建過程。下面是幾種常見的示例&#xff0c;實現上層 Makefile 對下層 Makefile 的控制。 直接調用&#xff1…

prompts提示詞經典模板

prompts.py 中的提示詞模板詳解 文件中定義了兩個核心提示詞模板&#xff1a;REASON_PROMPT 和 RELEVANT_EXTRACTION_PROMPT。這兩個模板在 DeepResearcher 的推理過程中扮演著關鍵角色。下面我將詳細解析這兩個模板的結構和功能。 REASON_PROMPT 詳解 REASON_PROMPT 是用于指…

使用python獲取電腦硬盤信息

import psutil# 獲取硬盤信息 disk_partitions psutil.disk_partitions() print(disk_partitions) for partition in disk_partitions:print(f"設備: {partition.device}")print(f"掛載點: {partition.mountpoint}")print(f"文件系統類型: {partitio…

HarmonyOS-ArkUI V2裝飾器: @Provider和@Consumer裝飾器:跨組件層級雙向同步

作用 我們在之前學習的那些控件中,各有特點,也各有缺陷,至今沒有痛痛快快的出現過真正能跨組件的雙向綁定的裝飾器。 比如 @Local裝飾器,不能跨組件@Param裝飾器呢,能跨組件傳遞,但是僅僅就是下一層組件接收參數。另外,它是單向傳遞,不可被重新賦值。如果您非要改值則…

索引下推(Index Condition Pushdown, ICP)

概念 索引下推是一種數據庫查詢優化技術&#xff0c;通過在存儲引擎層面應用部分WHERE條件來減少不必要的數據讀取。它特別適用于復合索引的情況&#xff0c;因為它可以在索引掃描階段就排除不符合全部條件的數據行&#xff0c;而不是將所有可能匹配的記錄加載到服務器層再進行…

idea在線離線安裝插件教程

概述 對于小白來說&#xff0c;剛使用idea時&#xff0c;還有很多不懂的地方&#xff0c;這里&#xff0c;簡單介紹下如何安裝插件。讓小白能容易上手全盤idea。 1、File -> Settings 2、找到 Plugins -> Marketplace 3、安裝 3.1、在線安裝 輸入想搜索的內容&#x…

豪越賦能消防安全管控,解鎖一體化內管“安全密碼”

在消防安全保障體系中&#xff0c;內部管理的高效運作是迅速、有效應對火災及各類災害事故的重要基礎。豪越科技憑借在消防領域的深耕細作與持續創新&#xff0c;深入剖析消防體系內部管理的痛點&#xff0c;以自主研發的消防一體化安全管控平臺&#xff0c;為行業發展提供了創…

ES6學習03-字符串擴展(unicode、for...of、字符串模板)和新方法()

一、字符串擴展 1. eg: 2.for...of eg: 3. eg: 二。字符串新增方法 1. 2. 3. 4. 5.

探索Streamlit在測試領域的高效應用:文檔讀取與大模型用例生成的完美前奏

大模型用例生成前置工作之文檔讀取——構建你的自動化測試基礎 在群友的極力推薦下&#xff0c;開始了streamlit的學習之旅。本文將介紹如何使用Streamlit開發一個多功能文檔處理工具&#xff0c;支持讀取、預覽、格式轉換和導出多種測試相關文檔&#xff08;YAML、JSON、DOCX…