数据结构 二叉堆 & 堆排序

【数据结构与算法】内部排序之三:堆排序(含完整源码) 堆排序、快速排序、归并排序(下篇会写这两种排序算法)的平均时间复杂度都为O(n*logn)。要弄清楚堆排序,就要先了解下二叉堆这种数据结构。本文不打算完全讲述二叉堆的所有操作,而是着重讲述堆排序中要用到的操作。比如我们建堆的时候可以采用堆的插入操作(将元素插入到适当的位置,使新的序列仍符合堆的定义)将元素一个一个地插入到堆中,但其实我们完全没必要这么做,我们有执行操作更少的方法,后面你会看到,我们基本上只用到了堆的删除操作,更具体地说,应该是删除堆的根节点后,将剩余元素继续调整为堆的操作。先来看二叉堆的定义 阅读详情

二叉堆,是一个满二叉树,满足堆的性质。即父节点大于等于子节点(max heap)或者是父节点小于等于子节点(min heap)。二叉堆的如上性质常用于优先队列(priority queue)或是用于堆排序。

由于max heap 与min heap类似,下文只针对min heap进行讨论和实现。


如上图,是根据字母的ASCII码建立的最小堆。

我们用数组对满二叉树采用宽度优先遍历存储堆结构,如下图所示:


从数组下标1开始存储堆,这样的处理方式可以得到如下性质:

1.堆中的每个父节点k,他的两个子节点为k*2和k*2+1

2.堆中的每个子节点k,他的父节点为k/2


堆的插入:当向堆中插入一个元素时,首先将新添加的元素放入数组的末尾,然后使用percolatingUp方法,将新添加的元素逐层向上移动至合适位置。如下图所示:


堆的删除:当将堆顶元素删除时,首先将数组中末尾的元素放入对顶,然后使用percolatingDown方法,将堆顶元素逐层向下移动至合适位置。如下图所示:


堆的构建:将对大小为k的数组,从第k/2个元素开始(第1个到第k/2个元素有子节点),依次使用porcelatingUp将元素向上调整,其时间复杂度O(k)。

堆排序的思想是:将待排序的数组转成堆(堆的构建),删除root节点(获取最小元素),重构(porcelatingDown),删除root节点(获取第二小元素),重构(porcelatingDown),...一直到堆中不再有元素。


堆操作的时间复杂度(N表示元素个数):

建堆:O(N)

添加:O(logN)

删除:O(logN)

堆排序:O(NlogN)


堆及堆排序的java实现:

/****************************************************************************
 *       This demonstrates binary heap operations along with the heapSort.
 *
 *****************************************************************************/
import java.util.*;

@SuppressWarnings("unchecked")
public class Heap<AnyType extends Comparable<AnyType>>
{
   private static final int CAPACITY = 2;

   private int size;            // Number of elements in heap
   private AnyType[] heap;     // The heap array

   public Heap()
   {
      size = 0;
      heap = (AnyType[]) new Comparable[CAPACITY];
   }

 /**
  * Construct the binary heap given an array of items.
  */
   public Heap(AnyType[] array)
   {
      size = array.length;
      heap = (AnyType[]) new Comparable[array.length+1];

      System.arraycopy(array, 0, heap, 1, array.length);//we do not use 0 index

      buildHeap();
   }
 /**
  *   runs at O(size)
  */
   private void buildHeap()
   {
      for (int k = size/2; k > 0; k--)
      {
         percolatingDown(k);
      }
   }
   private void percolatingDown(int k)
   {
      AnyType tmp = heap[k];
      int child;

      for(; 2*k <= size; k = child)
      {
         child = 2*k;

         if(child != size &&
            heap[child].compareTo(heap[child + 1]) > 0) child++;

         if(tmp.compareTo(heap[child]) > 0)  heap[k] = heap[child];
         else
                break;
      }
      heap[k] = tmp;
   }

 /**
  *  Sorts a given array of items.
  */
   public void heapSort(AnyType[] array)
   {
      size = array.length;
      heap = (AnyType[]) new Comparable[size+1];
      System.arraycopy(array, 0, heap, 1, size);
      buildHeap();

      for (int i = size; i > 0; i--)
      {
         AnyType tmp = heap[i]; //move top item to the end of the heap array
         heap[i] = heap[1];
         heap[1] = tmp;
         size--;
         percolatingDown(1);
      }
      for(int k = 0; k < heap.length-1; k++)
         array[k] = heap[heap.length - 1 - k];
   }

 /**
  * Deletes the top item
  */
   public AnyType deleteMin() throws RuntimeException
   {
      if (size == 0) throw new RuntimeException();
      AnyType min = heap[1];
      heap[1] = heap[size--];
      percolatingDown(1);
      return min;
	}

 /**
  * Inserts a new item
  */
   public void insert(AnyType x)
   {
      if(size == heap.length - 1) doubleSize();

      //Insert a new item to the end of the array
      int pos = ++size;

      //Percolate up
      for(; pos > 1 && x.compareTo(heap[pos/2]) < 0; pos = pos/2 )
         heap[pos] = heap[pos/2];

      heap[pos] = x;
   }
   private void doubleSize()
   {
      AnyType [] old = heap;
      heap = (AnyType []) new Comparable[heap.length * 2];
      System.arraycopy(old, 1, heap, 1, size);
   }

   public String toString()
   {
      String out = "";
      for(int k = 1; k <= size; k++) out += heap[k]+" ";
      return out;
   }

   public static void main(String[] args)
   {
      Heap<String> h = new Heap<String>();

      h.insert("p");
      h.insert("r");
      h.insert("i");
      h.insert("o");
      System.out.println(h);
      h.deleteMin();
      System.out.println(h);


      Heap<Integer> tmp = new Heap<Integer>();
      Integer[] a = {4,7,7,7,5,0,2,3,5,1};
      tmp.heapSort(a);
      System.out.println(Arrays.toString(a));
   }
}

参考:

1.http://www.cs.cmu.edu/~adamchik/15-121/lectures/Binary%20Heaps/heaps.html

2.http://en.wikipedia.org/wiki/Binary_heap

超详细的YOLOv8安装与测试指南:让计算机视觉任务变得简单 python3+、Anaconda3或Miniconda3 Ultralytics提供了多种安装方法,包括pip、conda和Docker。通过pip包安装最新稳定版的YOLOv8,或者克隆Ultralytics GitHub仓库以获取最新版本。Docker可用于在隔离容器中执行包,避免本地安装。 最简单直接的方式就是直接使用pip方法直接安装。 也可以直接从GitHub仓库安装包。如果你想要最新的开发版本,这可能会很有用。确保你的系统上安装了Git命令行工具 阅读详情

相关推荐

Python 格点数据插值到站点 最邻近插值 双线性插值

python 气象数据格点数据插值到站点,最邻近插值法,双线性插值法

好记性不如烂笔头 8459

数据结构-二叉堆

二叉堆是一种完全二叉树(除最后一层外,其它各层的结点数都达到最大个数,最后一层所有的结点都连续集中在最左边) 大顶堆 任何一个父节点的值,都大于或等于它左、右孩子节点的值 小顶堆 任何一个父节点的值,都小于或等于它左、右孩子节点的值 存储方式: 二叉堆可以使用数组来储存,如果数组从第1位开始存,数组中下标为 i 的节点的左子节点,就是下标为 i∗2 的节点,右子节点就是下标为 i∗2+1 的节点,父节点就是下标为 i/2 取整的节点 如果数组从第0位开始存,数组中下标为 i 的节点的左子节点,就是

weixin_41029286的博客 191

光模块基础知识【快速入门】02

光模块是用于交换机与设备之间传输的载体,是光纤通信系统中的核心器件。主要作用是发射端将设备的电信号转换成光信号。 光纤通道光模块和以太网光模块 光纤通道光模块 光纤通道(FC, Fiber Channel)是一种高速网络数据传输协议。光纤通道协议可以有序无损地传输原始数据,它主要用于在数据中心、电脑服务器、交换机与存储网络中进行数据传输。 FC光模块遵循FC协议,充当着光纤通道系统之间的接口,也是光纤存储网络设备间的接口。它们主要用于数据中心的光纤通道存储网络链接中。 FC光模块具有小型化和低.

Jin Hanquan的博客 3万+

数据结构---二叉堆

二叉堆(也成为堆)是一棵被完全填满的二叉树,有可能的例外实在底层,底层上的元素从左到右填入。这样的树称为完全二叉树。它可以用一个数组表示而不需要使用链。 对于数组中任一位置i上的元素,其左儿子在位置2i上,右儿子在左儿子后的单元(2i+1)中,它的父亲则在位置[i/2]上所以遍历该树所需要的操作极其简单。 堆序性质:任意节点小于它的所有后裔,也就是说最小元总可以在根处找到(即最小堆) ...

White的博客 425

【QT开发教程】使用Qt进行NFC编程

近场通信(NFC,Near Field Communication)技术广泛应用于现代设备中,例如智能手机、支付终端和门禁系统。Qt提供了一套完整的NFC模块,使开发者可以轻松地在应用程序中实现NFC功能。本文将介绍如何在Qt中进行NFC编程,包括基本概念、使用方法以及一些实际的示例。

科技改变人类,技术成就未来 1468

C# 上位机程序中的数据采集与存储技术:从采集到持久化的完整解决方案

本文系统讲解C#上位机程序如何实现设备数据采集与持久化。主要内容包括:1)多种数据采集方式(串口通信、Modbus、OPC等)及代码示例;2)详细对比不同存储技术(CSV、SQLite、关系型数据库等)的优缺点;3)提供SQLite等存储实现代码;4)推荐分层系统架构(采集-缓存-存储-可视化);5)性能优化建议(多线程采集、异步存储、批量写入等)。文章强调应根据项目需求选择合适的技术方案,构建高效稳定的数据采集存储闭环系统。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1025

基本数据结构:二叉堆(堆排序)

我们在解决问题时经常会遇到需要不断维护一段数据内最值的情况,用更精确的话来说就是:存在集合S,里面的元素可能会随时增加、删除、修改,而我们需要做到随时返回集合内的最值,如果采用遍历的方式维护最值,则每次维护都将遍历所有数据,其效率往往十分低下。为解决这个问题,我们就引入了一个新的数据结构——二叉堆。.........

yuhaomogui的博客 768

XXL-Job 分布式定时任务

XXL-JOB是一款轻量级分布式定时任务调度框架,采用调度中心与执行器分离架构,解决单机任务宕机、重复执行等问题。核心模块包括调度中心(管理任务配置、触发调度)和执行器(执行任务逻辑),支持集群部署保证高可用。框架提供丰富的任务触发规则、路由策略、阻塞策略及完善的运维能力,适用于多种业务场景如数据同步、定时推送等。安装时需准备MySQL数据库并初始化表结构,通过Docker部署调度中心服务。相比其他定时框架,XXL-JOB具有轻量化、可视化等优势,是中小企业的首选方案。

郭宝的博客 699

二叉堆

二叉堆是数据结构中优先队列的一种实现。二叉堆具有两个性质:结构性和堆序性。 1、结构性 二叉堆其实就是一棵完全二叉树。除了最底层之外,其余层都被完全填充。这个完全二叉树可以不使用指针,而使用数组来表示,其中a[0]的位置存储的是一个标记(sentinel),对于最小二叉堆a[0] =

xh 2610

运维工程师面试整理-安全常见安全漏洞及修复

暴露在互联网的服务和端口可能会成为攻击者的目标,例如开放的SSH、FTP、Telnet等。:攻击者通过注入恶意脚本,使其在其他用户的浏览器中执行,从而窃取用户信息或劫持用户会话。:通过插入恶意SQL代码,攻击者可以操纵应用程序的数据库查询,执行未授权的数据库操作。:展示你对新兴安全威胁和防护技术的了解和学习能力,如零信任架构、基于AI的安全分析等。在不同的服务器或沙盒环境中处理和存储上传的文件,避免在Web根目录下保存可执行文件。采用安全框架和标准(如OWASP、NIST),确保系统和应用的安全合规性。

不务正业的猿 923

31、贝叶斯认知建模与隐马尔可夫模型:理论与应用

本文探讨了贝叶斯认知建模与隐马尔可夫模型(HMM)的理论基础及其在认知科学和神经科学中的应用。重点介绍了贝叶斯定理和HMM的基本原理,并结合实际案例,如情绪识别系统和脑机接口(BCI),展示了它们在处理复杂认知任务中的强大能力。文章还讨论了贝叶斯-HMM模型的技术细节、优势与局限性,以及未来的发展前景。

meat5的博客 141

数据结构:二叉堆

一种存储方式:一维数组 性质1:完全二叉树(注意与满二叉树的区别) 性质2:按照数组下标索引元素的话,某个节点i的父节点为i/2(向下取整),左孩子为2*i,右孩子为2*i+1。 性质3:如果是最小堆,则二叉树中每个父节点都小于其两个子节点,两个子节点的大小没有要求。 主要支持操作:insert,extractMin(最小堆),shiftUp,shiftDown insert: 将元素直接放到数组末尾,再进行shiftUp操作 shiftUp:向当前最小堆插入元素后进行的操作。由于是插入到数组末尾,所以其可

weixin_44858471的博客 182

【四足机器人项目实战】四足机器人嵌入式硬件设计

系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 TODO:写完再整理 文章目录系列文章目录前言一、电源管理板设计及制作二、通讯中继板设计及制作三、力控无刷电机驱动板设计及制作1.磁场定向控制FOC控制原理2.电机转子位置、速度检测原理3.硬件CAN通讯原理 前言 认知有限,望大家多多包涵,有什么问题也希望能够与大家多交流,共同成长! 本文先对四足机器人–嵌入式硬件设计做个简单的介绍,具体内容后续再更,其他模块可以参考去我其他文章 提示:以下是本篇文章正文内容 一、电

qq_35635374的博客 1万+

数据结构-二叉堆&堆排序Java

二叉堆 堆排序 二叉堆 import java.util.Arrays; public class HeapOperator { public static void main(String[] args) { //上浮 int[] array0=new int[]{1,3,2,6,5,7,8,9,10,0}; upAdjust(array0); System.out.println(Arrays.toString(array0).

乾坤未定,你我皆是黑马 251

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

二叉堆-堆排序

堆排序(Heap Sort)是一种基于二叉堆(Binary Heap)数据结构的排序算法。它的核心思想是通过构建一个最大堆或最小堆,利用堆的性质逐步将堆顶元素(最大值或最小值)取出,从而实现排序。二叉堆的性质是堆排序的基础,理解这些性质是掌握堆排序的关键。由于堆是完全二叉树,因此可以用数组来表示堆。这种表示方法不仅节省空间,还能方便地通过索引访问父节点和子节点。i2 * i + 12 * i + 2假设有一个数组1710281001078堆化(Heapify)是将一个无序数组调整为堆的过程。

qq_44606649的博客 910

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

c++实现二叉堆及堆排序

一、什么是二叉堆

远走的兔子博客 3201

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

数据结构--二叉堆与堆排序

二叉堆的概念 二叉堆,BinaryHeap,是二叉树中的常见的一种结构。通常以最大堆和最小堆的形式呈现。最大堆指的是父节点大于等于孩子节点的value值,也就是说对于最大堆而言,根元素是二叉堆最大的元素。最小堆的概念是与最大堆的概念是相似的。

我只是一个单纯的2的博客 5071

Java实现的二叉堆以及堆排序详解

一、前言   二叉堆是一个特殊的堆,其本质是一棵完全二叉树,可用数组来存储数据,如果根节点在数组的下标位置为1,那么当前节点n的左子节点为2n,有子节点在数组中的下标位置为2n+1。二叉堆类型分为最大堆(大顶堆)和最小堆(小顶堆),其分类是根据父节点和子节点的大小来决定的,在二叉堆中父节点总是大于或等于子节点,该二叉堆成为最大堆,相反地称之为最小堆。因此,最大堆父节点键值大于或等于子节点,最小堆父节点键值小于或等于子节点。根据二叉堆的特点,二叉堆可以用来实现排序、有限队列等。堆排序就是利用二叉堆的特性来实现

rianple的博客 350

数据结构-二叉堆(大顶堆&小顶堆)

文章目录简介Java 实现时间复杂度一些疑问 简介 二叉堆就是一颗二叉树,是一颗完全二叉树,最直观表现一个二叉树左边最多比右边深 1 层,二叉堆我们常常讨论的就是大顶堆和小顶堆,其中大顶堆根结点最大,左右节点依次递归,小顶堆类似 二叉堆算是一种比较重要的数据结构,实际中我们的堆排序就涉及到二叉堆,它也是优先级队列的基础 所以这里我可以说下二叉堆的性质: 完全二叉树 完全二叉树比平衡二叉树条件更...

abcnull 的博客 2085

C语言实现优先队列、二叉堆和堆排序

查找和排序是数据结构与算法中不可或缺的一环,是前辈们在算法道路上留下的重要且方便的一些技巧,学习这些经典的查找和排序也能让我们更好和更快的解决问题。在这个专栏中我们会学习六大查找和十大排序的算法与思想,而本篇将详细讲解其中的堆排序;...

ZER00000001的博客 1464

python二叉堆

定义 二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树)或者是近似完全二元树(二叉树)。二叉堆有两种:最大堆和最小堆。最大堆:父结点的键值总是大于或等于任何一个子节点的键值; 最小堆:父结点的键值总是小于或等于任何一个子节点的键值。 二叉堆一般用数组来表示。如果根节点在数组中的位置是1,第n个位置的子节点分别在2n和 2n+1。因此,第1个位置的子节点在2和3,第2个位置的子节点在4和5。以此类推。这种基于1的数组存储方式便于寻找父节点和子节点。 二叉堆的根节点叫做堆顶。 最大堆和最小堆的特点

洪源的博客 1万+

数据结构 10 基础数据结构 二叉堆 堆排序算法详解

通过上一节的学习,我们了解到 二叉堆的本质还是一个完全二叉树 无序数组通过构造、通过下沉构造可以构造为最小堆 通过上浮构造可以构造为最大堆 来说今天的堆排序算法之前、首先请和我一起、再次了解一下二叉堆元素的删除 二叉堆删除元素 这里假设我们这里有这样的一个完全二叉树如下: 1、删除顶部1号元素【暂且放到尾部】、9号元素到达顶部 2、二叉堆进行自我结构的调整、省略调整步骤、9号元素...

Marc1999的博客 283

数据结构基础 之 二叉堆实现堆排序

堆实际上是一棵完全二叉树,也称二叉堆。本文首先对二叉堆的定义和相关概念给予阐述并针对堆排序图例给出算法单步演示,而后给出二叉堆以及堆排序的代码实现,文末结合实际代码实现给出算法要点分析。

稚枭天卓 1730

二叉堆和堆排序的python实现

一 二叉堆的实现 二叉堆本质上是一种完全二叉数: 最大堆:根节点为最大节点,任意的父节点都不小于其所有子节点 最小堆:根节点为最小节点,任意的父节点都不大于其所有子节点 二叉堆创建: 根据原数组,然后从最后一个非叶子节点开始,依次下沉,得到最后序列 二叉堆操作: 插入节点,位置为最后,然后根据情况上浮调整; 删除一般为堆顶的节点,然后最后节点临时补到堆顶位置,然后下沉调整 图比较麻烦就不画了,可以参考这篇文章: https://blog.youkuaiyun.com/xiao__jia__jia/article

清风徐来 693

进阶数据结构——二叉堆

二叉堆的核心是利用完全二叉树和堆性质实现高效的最值操作。高阶问题的突破口通常在于堆的变种(如二项堆、斐波那契堆)或堆的应用场景(如优先队列、Top-K 问题)。

ycs66的博客 883

二叉堆(彻底整明白堆排序)

前言:之前写过堆排序,因为对堆数据结构还是不够了解,懵懵逼逼的写完了堆排序,写完后,过一段时间就忘记了,究其原因,没有真正了解堆数据结构,于是…有了这篇文章 插入 构建 public class HeapTest { public static void main(String[] args) { int[] arr = {1, 3, 2, 6, 5, 7, 8, 9, 10, 0}; Heap heap = new Heap(arr); h.

qq_45796208的博客 636
上一篇: Java垃圾回收
下一篇: Java内存区域——JVM读书笔记<一>
Hooting
博客等级 码龄17年 11粉丝 44原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值