堆的原理以及实现O(lgn)

news2024/11/16 1:47:31

大家好,我是蓝胖子,我一直相信编程是一门实践性的技术,其中算法也不例外,初学者可能往往对它可望而不可及,觉得很难,学了又忘,忘其实是由于没有真正搞懂算法的应用场景,所以我准备出一个系列,囊括我们在日常开发中常用的算法,并结合实际的应用场景,真正的感受算法的魅力。

今天我们就来看看堆这种数据结构。

源码已经上传到github

https://github.com/HobbyBear/codelearning/tree/master/heap

原理

在详细介绍堆之前,先来看一种场景,很多时候我们并不需要对所有元素进行排序,而只需要取其中前topN的元素,这样的情况如果按性能较好的排序算法,比如归并或者快排需要n*log( n)的时间复杂度,n为数据总量,排好序后取出前N条数据,而如果用堆这种数据结构则可以在n*log(N)的时间复杂度内找到这N条数据,N的数据量远远小于数据总量n。

接着我们来看看堆的定义和性质,堆是一种树状结构,且分为最小堆和最大堆,最大堆的性质有父节点大于左右子节点,最小堆的性质则是父节点小于左右子节点。如下图所示:

image.png

并且堆是一颗完全二叉树,完全二叉树的定义如下:

若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。

因为结点都集中在左侧,所以我们可以从上到下,从左到右对堆中节点进行标号,如下图所示:

image.png

从0开始对堆中节点进行标号后,可以得到以下规律:

父节点标号 = (子节点标号-1)/2
左节点标号 = 父节点标号 *2 + 1
右节点标号 = 父节点标号 *2 + 2

有了标号和父子节点的标号间的关系,我们可以用一个数组来保存堆这种数据结构,下面以构建一个最大堆为例,介绍两种构建堆的方式。

HeapInsert

heapInsert的方式是从零开始,逐个往堆中插入数组中的元素,并不断调整新的节点,让新节点的父节点满足最大堆父节点大于其子节点的性质,这个调整的过程被称作ShiftUp。当数组中元素全部插入完成时,就构建了一个最大堆。代码如下:

func HeapInsert(arr []int) *Heap {  
   h := &Heap{arr: make([]int, 0, len(arr))}  
   for _, num := range arr {  
      h.Insert(num)  
   }  
   return h  
}

Heapify

heapify的方式是假设数组已经是一个完全二叉树了,然后找到树中的最后一个非叶子节点,然后通过比较它与其子节点的大小关系,让其满足最大堆的父节点大于其子节点的性质,这样的操作被称作ShifDown,对每个非叶子节点都执行ShifDown操作,直至根节点,这样就达到了将一个普通数组变成一个堆的目的。

如果堆的长度是n,那么最后一个非叶子节点是 n/2 -1 ,所以可以写出如下逻辑,

func Heapify(arr []int) *Heap {  
   h := &Heap{arr: arr}  
   lastNotLeaf := len(arr)/ 2 -1  
   for i:= lastNotLeaf;i >= 0; i-- {  
      h.ShiftDown(i)  
   }  
   return h  
}

取出根节点

取出根节点的逻辑比较容易,将根节点结果保存,之后让它与堆中最后一个节点交换位置,然后从索引0开始进行ShiftDown操作,就又能让整个数组变成一个堆了。

func (h *Heap) Pop() int {  
   num := h.arr[0]  
   swap(h.arr, 0, len(h.arr)-1)  
   h.arr = h.arr[:len(h.arr)-1]  
   h.ShiftDown(0)  
   return num  
}

ShiftUp,ShiftDown实现

下面我将shiftUp和shiftDown的源码展示出来,它们都是一个递归操作,因为在每次shiftUp或者shiftDown成功后,其父节点或者子节点还要继续执行shifUp或shiftDown操作。

// 从标号为index的节点开始做shifUp操作  
func (h *Heap) ShiftUp(index int) {  
   if index == 0 {  
      return  
   }  
   parent := (index - 1) / 2  
   if h.arr[parent] < h.arr[index] {  
      swap(h.arr, parent, index)  
      h.ShiftUp(parent)  
   }  
}  
  
// 从标号为index的节点开始做shifDown操作  
func (h *Heap) ShiftDown(index int) {  
   left := index*2 + 1  
   right := index*2 + 2  
   if left < len(h.arr) && right < len(h.arr) {  
      if h.arr[left] >= h.arr[right] && h.arr[left] > h.arr[index] {  
         swap(h.arr, left, index)  
         h.ShiftDown(left)  
      }  
      if h.arr[right] > h.arr[left] && h.arr[right] > h.arr[index] {  
         swap(h.arr, right, index)  
         h.ShiftDown(right)  
      }  
   }  
   if left >= len(h.arr) {  
      return  
   }  
   if right >= len(h.arr) {  
      if h.arr[left] > h.arr[index] {  
         swap(h.arr, left, index)  
         h.ShiftDown(left)  
      }  
   }  
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1047932.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uCOSIII实时操作系统(重入函数,调度算法,嵌入式系统中断)

目录 可重入函数和不可重入函数&#xff1a; 基于优先级的调度算法&#xff1a; 嵌入式系统中断&#xff1a; 可重入函数和不可重入函数&#xff1a; 函数可重入是指一函数可以被多个任务调用&#xff0c;而不需要担心在任务切换的过程中&#xff0c;代码的执行会产生错误的…

实用网站合集

目录 1.工具网站合集2.技术类合集1.技术网站2.C3.计算机相关4.Java5.前端 收藏夹里有很多好用的网站&#xff0c;分类整理下&#xff0c;方便日后使用。 1.工具网站合集 阿里巴巴图标库&#xff1a;图标资源。pexels&#xff1a;壁纸、视频。unsplash&#xff1a;壁纸。pixabay…

基于cv2识别图像实现jd滑动块验证

这里写目录标题 出现条件&#xff1a;解决方案&#xff1a;获取滑动的距离滑动验证 本教程无任何意向&#xff0c;纯纯的技术娱乐 虽然小概率出现问题&#xff0c;加入重试机制后&#xff0c;基本没出现过问题 注意&#xff1a;这里获取的距离与实际的距离不相同&#xff0c;本…

mysql面试题1:MySQL有哪些常见存储引擎?MySQL默认是哪个存储引擎?

该文章专注于面试&#xff0c;面试只要回答关键点即可&#xff0c;不需要对框架有非常深入的回答&#xff0c;如果你想应付面试&#xff0c;是足够了&#xff0c;抓住关键点 面试官&#xff1a;MySQL有哪些常见存储引擎&#xff1f; MySQL有以下几种常见的存储引擎&#xff1…

智慧公厕自动化保洁系统,让公共厕所实现7*24 持续整洁

随着科技的不断进步&#xff0c;越来越多的创新方案应用于各个领域&#xff0c;公共厕所的智慧化也不例外。本文重点介绍智慧公厕源头厂家广州中期科技有限公司&#xff0c;大量案例项目中所使用的智慧公厕自动化保洁系统&#xff0c;能有效地节省人力&#xff0c;并保持公共厕…

抽象轻松的java——简单的购物车系统

public class GoodsShop {public static void main(String[] args) {System.out.println("欢迎来到购物车管理系统");obj [] arr new obj[50];//obj[50]为购物车的数量上限obj obj new obj();//调用objScanner scanner new Scanner(System.in);//输入while (true)…

【C++14保姆级教程】数位分割符、函数返回值推导

文章目录 前言一、数位分割符&#xff08;Digit Separators&#xff09;1.1 数位分割符是什么&#xff1f;1.2 作用1.3 示例代码11.4 示例代码21.5 数位分隔符的优势 二、函数返回值推导&#xff08;Function Return Type Deduction&#xff09;2.1 函数返回值推导是什么&#…

[NOIP2011 提高组] 铺地毯

[NOIP2011 提高组] 铺地毯 题目描述 为了准备一个独特的颁奖典礼&#xff0c;组织者在会场的一片矩形区域&#xff08;可看做是平面直角坐标系的第一象限&#xff09;铺上一些矩形地毯。一共有 n n n 张地毯&#xff0c;编号从 1 1 1 到 n n n。现在将这些地毯按照编号从小…

【LeetCode热题100】--142.环形链表II

142.环形链表II 使用哈希表&#xff1a; 遍历链表中的每个节点&#xff0c;并将它记录下来&#xff0c;一旦遇到了此前遍历过的节点&#xff0c;就可以判定链表中存在环 /*** Definition for singly-linked list.* class ListNode {* int val;* ListNode next;* …

Unity Urp无线延申的网格效果

无线延申的网格 该项目必须是再Urp项目 shader代码实现 Shader "Unlit/infTutorial1" {Properties{_Alpha ("Alpha", Range(0, 0.5)) 0.5}SubShader{Tags{"RenderPipeline""UniversalRenderPipeline""RenderType""…

操作系统监控工具

在当今复杂、动态的网络环境中&#xff0c;服务器管理员根据其要求在各种操作系统上工作&#xff0c;操作系统是管理硬件和软件资源的基本系统软件&#xff0c;它是硬件与您运行的不同应用程序之间的接口&#xff0c;保持操作系统更新至关重要&#xff0c;最重要的是&#xff0…

SDI-12协议与STM32 进行uart通信

场景是用stm32与一款温湿度传感器通信&#xff0c;不过是基于SDI-12协议&#xff0c;SDI-12时序和UART类似&#xff0c;故采用UART传输&#xff0c;原理图如下 其中DIR_OUT_SDI是一个IO引脚&#xff0c;控制UART_TX_SDI是否使能&#xff0c;U10是三态门IC&#xff0c;即拉低DIR…

测试网页调用本地可执行程序(续1:解析参数中的中文编码)

学习测试网页调用本地可执行程序还遗留一个问题&#xff0c;即网页中调用带中文参数的命令时&#xff0c;本地可执行程序接收到的参数字符串里的中文都转换成了编码模式&#xff0c;看起来如下所示&#xff1a; <a href TestPageCall:-a你好>启动测试程序</a><…

destoon根据查询标题小于5个字符的数据进行删除

最近客户有个需求&#xff0c;就是他采集的时候&#xff0c;标题有些小于5字符的短标题的垃圾数据&#xff0c;进行清空处理&#xff0c;让我进行批量删除。废话不多说&#xff0c;接着干。 首先在dt根目录新建delmysql.php文件&#xff0c;代码如下&#xff1a; <?php r…

机器学习——KNN算法流程详解(以iris为例)

目 录 前情说明 问题陈述 数据说明 KNN算法流程概述 代码实现 前情说明 本书基于《特征工程入门与入门与实践》庄家盛 译版P53也K最近邻&#xff08;KNN&#xff09;算法进行讲解 问题陈述 Iris 鸢尾花数据集内包含 3 类分别为山鸢尾&#xff08;Iris-setosa&#xff09…

99%的亚马逊运营都不知道爆单小技巧——社媒促销代码

社交媒体促销代码是促进产品在亚马逊上销售的最有效推广方式之一&#xff0c;有了这个营销工具&#xff0c;卖家可以在社交媒体上宣传您的产品&#xff0c;并通过社交媒体和网红营销内容将促销代码分享给买家&#xff0c;进行更具针对性的促销。 一、什么是社交媒体促销代码 社…

BoxUVMap处理参考

该Shader的目标是让物体的位置作为UV&#xff0c;在物体自身UV没有正确展开的情况下保证物体各个面能够避免贴图拉伸&#xff0c;比较适合Box型的物体。本来Position节点和Normal Vector节点应该选择Object选项&#xff0c;但是当时选择了World选项&#xff0c;主要是应对项目的…

在亚马逊云科技Amazon SageMaker上部署构建聊天机器人的开源大语言模型

开源大型语言模型&#xff08;LLM&#xff09;已经变得流行起来&#xff0c;研究人员、开发人员和组织都可以使用这些模型来促进创新和实验。这促进了开源社区开展合作&#xff0c;从而为LLM的开发和改进做出贡献。开源LLM提供了模型架构、训练过程和训练数据的透明度&#xff…

超大表格组件滚动渲染优化

引用自 摸鱼wiki 背景 业务中需要渲染一个最多有100列的表格&#xff0c;由于表格使用原生dom实现&#xff0c;因此会出现同屏有近1000个单元格同时绘制&#xff0c;在快速滑动时页面会产生卡顿&#xff0c;影响用户体验。 方案 如下图所示&#xff0c;由于用户显示屏区域有…

LeetCode算法二叉树—222. 完全二叉树的节点个数

目录 222. 完全二叉树的节点个数 - 力扣&#xff08;LeetCode&#xff09; 代码&#xff1a; 运行结果&#xff1a; 给你一棵 完全二叉树 的根节点 root &#xff0c;求出该树的节点个数。 完全二叉树 的定义如下&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能…