堆的建立、插入、出堆、堆化、topk问题、堆排序(C语言实现)

2024-09-03 01:12

本文主要是介绍堆的建立、插入、出堆、堆化、topk问题、堆排序(C语言实现),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

堆的建立、插入、出堆、堆化、topk问题、堆排序

  • 使用数组来存储堆
    • 堆顶为序号0,堆底为序号 size - 1
  • 假设树为完全二叉树,当前节点和双亲节点的关系可以通过公式表达
// 小顶堆: 对 heaptifyUp 和 heaptifyDown 函数的逻辑进行一些调整。
void initHeap(float **arr, int *size) { *arr = (float *)malloc(sizeof(float) * MAX_SIZE); *size = 0; }
void peekTop(float *arr, int size, float *x) { if (size <= 0) return; *x = arr[0]; }
void getParent(int i, int *p_idx) { *p_idx = (i - 1) / 2; }
void getLeftChild(int i, int *lc_idx) { *lc_idx = 2 * i + 1; }
void getRightChild(int i, int *rc_idx) { *rc_idx = 2 * i + 2; }
void heaptifyUp(float *arr, int idx) { // 比较当前节点与其父节点的大小。如果当前节点的值小于父节点的值,则交换它们,并继续向上调整。int cur = idx;while (cur > 0) {  // 只要 cur 不是根节点int par; getParent(cur, &par); if (arr[cur] >= arr[par]) break; // 如果当前节点大于等于父节点,退出循环float tmp = arr[cur]; arr[cur] = arr[par]; arr[par] = tmp; cur = par;  // 交换当前节点和父节点, 更新 cur 为父节点索引}
}
void heaptifyDown(float *arr, int size, int idx) { // 比较当前节点与其左右子节点的大小。选择最小的子节点,如果当前节点大于这个子节点,则交换它们,并继续向下调整。int cur = idx;while (true) {int lc, rc, minidx = cur; getLeftChild(cur, &lc); getRightChild(cur, &rc);if (lc < size && arr[lc] < arr[minidx]) { minidx = lc; } // 找到当前节点和左子节点中的最小值if (rc < size && arr[rc] < arr[minidx]) { minidx = rc; } // 找到当前节点和右子节点中的最小值if (minidx == cur) break; // 如果当前节点是最小值,退出循环float tmp = arr[cur]; arr[cur] = arr[minidx]; arr[minidx] = tmp; cur = minidx;  // 交换当前节点和最小值节点, 更新 cur 为新的索引}
}
void pushHeap(float *arr, int *size, float x) {if ((*size) >= MAX_SIZE) return; // 如果堆已满,直接返回arr[*size] = x; (*size)++; // 将新元素放在堆的最后一个位置heaptifyUp(arr, (*size) - 1); // 重新调整堆
}
void popHeap(float *arr, int *size, float *val) {if ((*size) <= 0) return; // 如果堆为空,直接返回*val = arr[0]; arr[0] = arr[(*size) - 1]; // 将堆的最后一个元素放在堆顶(*size)--; heaptifyDown(arr, *size, 0); // 重新调整堆
}
void buildHeap(float *arr, int size){// 使用heaptifyDown的原因是,如果使用 heaptifyUp从树的底部向上调整,每个节点在最坏情况下可能需要一直移到树的根部(并且底部的节点数量多)。// 这意味着可能需要执行更多的比较和交换操作。而如果我们从上往下调整,每个节点最多只需要向下移动几层(通常是树的高度),这使得整体效率非常高。for (int i = size / 2 - 1; i >= 0; i--) heaptifyDown(arr, size, i); // 从最后一个非叶子节点(size/2 - 1)开始,向上调整堆;
}
void freeHeap(float **arr) { if (*arr) { free(*arr); *arr = NULL; } }
void top_k(float *arr, int size, float *res, int k) {if (k <= 0 || k > size) return;float *heap = (float *)malloc(sizeof(float) * k); int heap_size = 0;for (int i = 0; i < k; i++){ pushHeap(heap, &heap_size, arr[i]); } //  // 初始化堆,放入前 k 个元素for (int i = k; i < size; i++){ if (arr[i] > heap[0]) { float tmp; popHeap(heap, &heap_size, &tmp); pushHeap(heap, &heap_size, arr[i]); } } // 处理剩余的元素for (int i = 0; i < k; i++) { popHeap(heap, &heap_size, &res[k - 1 - i]); } // 将堆中的元素按降序输出到 res 数组freeHeap(&heap);
}
// parallel: 在构建堆时,并行化处理多个子树的下沉操作
void heap_sort(float *heap, int size){ // 堆排序,从大道小排序buildHeap( heap, size); // 构建小顶堆while (size > 1) {float tmp = heap[0]; heap[0] = heap[size - 1]; heap[size - 1] = tmp; size--; // 将堆顶元素与堆的最后一个元素交换,每次循环最小的元素被调整到末尾,堆的大小减1heaptifyDown(heap, size, 0); // 从堆顶开始重新调整堆}freeHeap(&heap);
} 大顶堆
//void initHeap(float **arr, int *size) { *arr = (float *)malloc(sizeof(float) * MAX_SIZE); *size = 0; } // 初始化堆的大小为0
//void peekTop(float *arr, int size, float *x) { if (size <= 0) return ; *x = arr[0]; }
//void getParent(int i, int *p_idx) { *p_idx = (i - 1) / 2; }
//void getLeftChild(int i, int *lc_idx) { *lc_idx = 2 * i + 1; }
//void getRightChild(int i, int *rc_idx) { *rc_idx = 2 * i + 2; }
//void heaptifyUp(float *arr, int idx){
//    int cur = idx;
//    while (cur > 0){  // 只要 cur 不是根节点
//        int par; getParent(cur, &par); if (arr[cur] < arr[par]) break; // 如果当前节点小于父节点,退出循环
//        float tmp = arr[cur]; arr[cur] = arr[par]; arr[par] = tmp; cur = par;  // 交换当前节点和父节点
//    }
//}
//void heaptifyDown(float *arr, int size, int idx){
//    int cur = idx;
//    while (true){
//        int lc, rc, maxidx = cur; getLeftChild(cur, &lc); getRightChild(cur, &rc);
//        if (lc < size && arr[lc] > arr[maxidx]) { maxidx = lc;} // 找到当前节点和左子节点中的最大值
//        if (rc < size && arr[rc] > arr[maxidx]) { maxidx = rc;} // 找到当前节点和右子节点中的最大值
//        if (maxidx == cur) break; // 如果当前节点是最大值,退出循环
//        float tmp = arr[cur]; arr[cur] = arr[maxidx]; arr[maxidx] = tmp; cur = maxidx; // 交换当前节点和最大值节点
//    }
//}
//void pushHeap(float *arr, int *size, float x){
//    if ((*size) >= MAX_SIZE) return; // 如果堆已满,直接返回
//    arr[*size] = x; (*size)++; // 将新元素放在堆的最后一个位置
//    heaptifyUp(arr, (*size) - 1); // 重新调整堆
//}
//void popHeap(float *arr, int *size, float *val){
//    if ((*size) <= 0) return; // 如果堆为空,直接返回
//    *val = arr[0];
//    arr[0] = arr[(*size) - 1]; // 将堆的最后一个元素放在堆顶
//    (*size)--;
//    heaptifyDown(arr, *size,0); // 重新调整堆
//}
//void freeHeap(float **arr) { if (*arr) { free(*arr); *arr = NULL; } }

这篇关于堆的建立、插入、出堆、堆化、topk问题、堆排序(C语言实现)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1131599

相关文章

Spring Boot 实现 IP 限流的原理、实践与利弊解析

《SpringBoot实现IP限流的原理、实践与利弊解析》在SpringBoot中实现IP限流是一种简单而有效的方式来保障系统的稳定性和可用性,本文给大家介绍SpringBoot实现IP限... 目录一、引言二、IP 限流原理2.1 令牌桶算法2.2 漏桶算法三、使用场景3.1 防止恶意攻击3.2 控制资源

springboot下载接口限速功能实现

《springboot下载接口限速功能实现》通过Redis统计并发数动态调整每个用户带宽,核心逻辑为每秒读取并发送限定数据量,防止单用户占用过多资源,确保整体下载均衡且高效,本文给大家介绍spring... 目录 一、整体目标 二、涉及的主要类/方法✅ 三、核心流程图解(简化) 四、关键代码详解1️⃣ 设置

Nginx 配置跨域的实现及常见问题解决

《Nginx配置跨域的实现及常见问题解决》本文主要介绍了Nginx配置跨域的实现及常见问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来... 目录1. 跨域1.1 同源策略1.2 跨域资源共享(CORS)2. Nginx 配置跨域的场景2.1

Python中提取文件名扩展名的多种方法实现

《Python中提取文件名扩展名的多种方法实现》在Python编程中,经常会遇到需要从文件名中提取扩展名的场景,Python提供了多种方法来实现这一功能,不同方法适用于不同的场景和需求,包括os.pa... 目录技术背景实现步骤方法一:使用os.path.splitext方法二:使用pathlib模块方法三

CSS实现元素撑满剩余空间的五种方法

《CSS实现元素撑满剩余空间的五种方法》在日常开发中,我们经常需要让某个元素占据容器的剩余空间,本文将介绍5种不同的方法来实现这个需求,并分析各种方法的优缺点,感兴趣的朋友一起看看吧... css实现元素撑满剩余空间的5种方法 在日常开发中,我们经常需要让某个元素占据容器的剩余空间。这是一个常见的布局需求

HTML5 getUserMedia API网页录音实现指南示例小结

《HTML5getUserMediaAPI网页录音实现指南示例小结》本教程将指导你如何利用这一API,结合WebAudioAPI,实现网页录音功能,从获取音频流到处理和保存录音,整个过程将逐步... 目录1. html5 getUserMedia API简介1.1 API概念与历史1.2 功能与优势1.3

Java实现删除文件中的指定内容

《Java实现删除文件中的指定内容》在日常开发中,经常需要对文本文件进行批量处理,其中,删除文件中指定内容是最常见的需求之一,下面我们就来看看如何使用java实现删除文件中的指定内容吧... 目录1. 项目背景详细介绍2. 项目需求详细介绍2.1 功能需求2.2 非功能需求3. 相关技术详细介绍3.1 Ja

使用Python和OpenCV库实现实时颜色识别系统

《使用Python和OpenCV库实现实时颜色识别系统》:本文主要介绍使用Python和OpenCV库实现的实时颜色识别系统,这个系统能够通过摄像头捕捉视频流,并在视频中指定区域内识别主要颜色(红... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间详解

PostgreSQL中MVCC 机制的实现

《PostgreSQL中MVCC机制的实现》本文主要介绍了PostgreSQL中MVCC机制的实现,通过多版本数据存储、快照隔离和事务ID管理实现高并发读写,具有一定的参考价值,感兴趣的可以了解一下... 目录一 MVCC 基本原理python1.1 MVCC 核心概念1.2 与传统锁机制对比二 Postg

SpringBoot整合Flowable实现工作流的详细流程

《SpringBoot整合Flowable实现工作流的详细流程》Flowable是一个使用Java编写的轻量级业务流程引擎,Flowable流程引擎可用于部署BPMN2.0流程定义,创建这些流程定义的... 目录1、流程引擎介绍2、创建项目3、画流程图4、开发接口4.1 Java 类梳理4.2 查看流程图4