数据结构 二叉堆 & 堆排序

【数据结构与算法】内部排序之三:堆排序(含完整源码) 堆排序、快速排序、归并排序(下篇会写这两种排序算法)的平均时间复杂度都为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

产品经理如何运用AI提升工作效率 AI技术的应用为产品经理的工作流程带来了显著的效率提升。从需求收集到产品上线,AI可以在多个阶段提供智能化支持,帮助产品经理更好地理解用户需求、优化产品设计、提高开发和测试效率。在未来,随着AI技术的不断发展,产品经理将能够更加高效地管理产品生命周期,为用户提供更优质的产品体验。应用 | AI + 千行百业欢迎关注我的后续博文,我将分享更多关于人工智能、自然语言处理和计算机视觉的精彩内容。 阅读详情

相关推荐

海康摄像头V3.4 升级改造VUE3

摘要:本文介绍了一个基于Vue3的海康威视摄像头组件封装方案。针对官方仅提供HTML版本SDK的问题,作者通过封装实现了Vue3组件化集成,解决了iframe/webview引入方式的弊端。组件核心功能包括实时预览、本地录像、录像下载、截图抓拍等,并优化了SDK初始化逻辑(单例模式)、定位问题修复和错误处理机制。关键技术点包括:1)SDK插件容器定位修复;2)录像下载进度监控;3)多格式图片数据处理;4)多窗口场景下的SDK实例管理。该组件可直接通过npm安装使用,提供了完善的API和事件接口,显著提升了海

LINLINLINShi的博客 113

数据结构-二叉堆

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

weixin_41029286的博客 191

避开ANSYS SOLID65钢筋模拟的坑:从材料TB到实常数R的完整配置清单

本文详细解析了ANSYS SOLID65单元在钢筋混凝土模拟中的关键配置与优化技巧,涵盖材料TB设置、实常数R配置及收敛性优化。特别针对钢筋建模的分布式钢筋模型进行深度解析,提供实战验证的参数设置手册,帮助工程师避免常见错误,提升模拟精度与效率。

weixin_30898555的博客 364

数据结构---二叉堆

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

White的博客 425

Appsflyer S2S事件上报实战:从参数获取到避坑指南(附Firebase对比)

本文详细解析了Appsflyer S2S事件上报的实战技巧,包括核心参数获取、测试环境搭建、生产环境最佳实践以及高级场景处理。通过对比Firebase的事件上报机制,帮助开发者高效避坑并优化数据上报流程,提升应用分析与营销效果。

egg99的博客 884

ROS Noetic下Gazebo仿真:从零搭建两轮差速机器人(含ros_control配置避坑指南)

本文详细介绍了在ROS Noetic环境下,使用Gazebo从零搭建两轮差速机器人并进行仿真的完整流程。核心内容包括利用Xacro进行模块化建模,并重点解析了通过ros_control框架配置机器人运动控制的详细步骤与常见避坑指南,帮助开发者成功实现机器人在仿真环境中的差速驱动与运动控制。

game4的博客 620

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

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

yuhaomogui的博客 768

保姆级教程:用YOLOv8n模型在RKNN和Horizon平台完成目标检测(附C++部署代码与性能实测)

本文提供了一份详尽的YOLOv8n模型在RKNN和Horizon平台上的部署指南,涵盖环境配置、模型优化、跨平台适配及性能调优。通过实战案例和C++部署代码,帮助开发者在嵌入式设备上高效实现目标检测,显著提升推理性能。

weixin_42659194的博客 468

二叉堆

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

xh 2610

彻底摆脱文献只能读开头的痛苦!这款文献检索神器真能帮你跨越文献付费限制(附实操演示)

大家是不是有过这样的经历,好不容易通过关键词搜到了和自己主题高度相关的文献,想要快速获取文献信息,推进研究进度,却又因为付费或者需订阅才能下载PDF,而被劝退。粘贴完成后,点击搜索,搜索结果页面会显示这篇文献的相关信息,有的文献有“下载PDF”,有的文献则只有“求助PDF”,不管是哪种情况,直接点击进入;我这里点击的是“下载PDF”,接着它会跳转页面。我用 Book 学术下载过不少付费文献,实测下来 80% 左右的文献,都能通过它的求助方式成功获取到,只有少部分文献等待的时间会稍微久一些或者没办法下载。

qq_64378896的博客 164

Wi-Fi QoS中AIFSN/CWmin/CWmax/TxOP参数是怎样计算的?

802.11e/WMM的EDCA机制通过AIFS、CWmin/CWmax和TxOP三组参数实现业务优先级控制。AIFS决定最短等待时间(AIFS=SIFS+AIFSN×SlotTime),CWmin/CWmax定义退避范围(2^ECW-1),TxOP设置最大占用时长(32µs单位)。默认配置中,语音业务(VO)优先级最高,其AIFSN最小(2)、CW范围最小(3-7)、TxOP适中(1.504ms);视频(VI)次之;普通数据(BE)和后台(BK)优先级最低。调优需根据网络特性调整参数:VoIP可降低AIF

1042484520@qq.com(邮箱) 1746

数据结构:二叉堆

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

weixin_44858471的博客 182

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

数据结构-二叉堆&堆排序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

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

二叉堆-堆排序

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

qq_44606649的博客 910

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

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

一、什么是二叉堆

远走的兔子博客 3201

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

二叉堆的概念 二叉堆,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

【算法与数据结构】二叉堆和堆排序

构建堆 堆本身也是个二叉树,有两个限制: 堆必须是完全二叉树 堆中任一父结点的值大于其左右两子节点的值 因为完全二叉树中,数据排列顺序是从上而下,从左至右,所以可以用数组的形式保存数据。通常根结点作为数组的 0 号元素,其左右孩子分别是 2 号、3 号元素,以此类推。 保证一个元素符合要求 保证一个元素符合要求的过程,可以叫做 heapify。其顺序是: 如果元素超限,退出 比较元素值及其左...

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

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值