数据结构 二叉堆 & 堆排序

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

从Applied Intelligence被拒到The Visual Computer录用:我的计算机视觉论文投稿时间线全记录(含详细修改意见) 本文详细记录了作者从Applied Intelligence被拒到The Visual Computer成功发表计算机视觉论文的全过程,重点分享了如何将模糊的拒稿理由转化为具体改进方案。文章包含技术改进细节、写作调整策略以及期刊选择经验,为计算机视觉领域的研究者提供了实用的投稿指南。 阅读详情

相关推荐

深入解析DDR5 SDRAM的ODT模式:时序图与状态表实战指南

本文深入解析了DDR5 SDRAM的ODT模式,详细阐述了其五种工作状态及其在读写操作中的动态切换逻辑。通过解读JESD79-5标准中的时序图与状态表,并结合模式寄存器配置实战,为硬件工程师和爱好者提供了优化信号完整性、提升系统稳定性的关键指南。

gpu4optimizer的博客 699

数据结构-二叉堆

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

weixin_41029286的博客 191

LangGraph实战:用Plan-and-Execute模式5步搭建智能问答机器人(附Tavily搜索集成)

本文详细介绍了如何利用LangGraph的Plan-and-Execute模式,通过规划、执行、动态调整三个核心阶段,构建一个能够处理复杂多步骤问题的智能问答机器人。文章提供了从环境配置、状态管理到核心节点(规划、执行、重新规划)实现的完整实战指南,并集成了Tavily搜索工具,展示了如何将智能任务规划应用于实际信息查询场景。

weixin_29258297的博客 341

数据结构---二叉堆

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

White的博客 425

Ansys Lumerical | 薄膜铌酸锂电光调制器的仿真与优化

本文详细介绍了使用Ansys Lumerical进行薄膜铌酸锂电光调制器仿真与优化的全流程。从基础原理到电学仿真、光学模拟技巧,再到设计优化实战经验,帮助工程师掌握这一先进光电器件的仿真方法。重点解析了薄膜铌酸锂的Pockels效应和Mach-Zehnder结构设计,并提供了常见问题排查指南和最新发展动态。

vulkan6gpu的博客 1197

adams案例分析_案例1(麦弗逊悬架子系统创建)

本文字数3292字83图,建议阅读时间26分钟首先看下案例1的麦弗逊悬架数模结构就不细讲了,从数模上主要是获取硬点坐标(铰接点、安装点、参考点)及大部件结构(副车架、摆臂、转向节等实际运动过程中会产生变形的部件,在ADAMS Car中我们就可以用柔性体来搭建)再来回顾下上一篇讲到的模型元素1、Hardpoint——硬点(只有位置没有方向)2、Parameter Variable——参数...

weixin_39609407的博客 6476

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

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

yuhaomogui的博客 768

深入解析FPGA中的GTX高速收发器架构与设计原理

本文深入解析了FPGA中GTX高速收发器的核心架构与设计原理。文章将GTX比作数据“高速公路”,详细拆解了其PMA(物理媒介适配层)与PCS(物理编码子层)的双层结构,阐述了串并转换、时钟恢复等关键技术,并提供了时钟源选型(QPLL/CPLL)、上电复位流程及信号完整性调试等实战指南,是掌握高速接口设计的必备知识。

f6g7h8i9j的博客 219

二叉堆

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

xh 2610

2、探秘储备池计算:原理、应用与前沿趋势

储备池计算(Reservoir Computing)作为一种新兴的计算方法,起源于计算神经科学和机器学习领域,现已广泛应用于非线性动力系统理论、物理学、材料科学、生物学和机器人学等多个领域。其核心优势在于概念简洁性,通过利用高维动态系统的非线性响应,将学习过程集中在读出层,避免了传统循环神经网络(RNN)训练的复杂性。储备池计算的发展方向主要包括拓展到非线性动态系统和利用物理动态系统作为计算资源(PRC),后者有望突破冯·诺依曼瓶颈,实现边缘计算。理论方面,储备池计算与人类大脑的信息处理方式密切相关,并推动

ggg99的专栏 734

生产环境中redis的SCAN命令如何替代KEYS命令?

本文介绍了使用SCAN命令替代KEYS的完整方案。SCAN通过游标分批迭代,避免KEYS命令遍历整个键空间导致的阻塞风险。文章详细说明了SCAN的基础语法、迭代流程和Java实现示例,强调必须关闭Cursor避免连接泄漏。针对生产环境,提供了COUNT参数调优、客户端去重、集群模式适配等优化建议,并列举了典型错误场景。SCAN通过分批次迭代和游标管理,可安全实现高性能键空间遍历。全文150字。

DN金猿的博客 179

数据结构:二叉堆

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

weixin_44858471的博客 182

学Simulink--基于风力发电系统的场景实例:海上风电场在复杂海况下的动态响应仿真

本实例将创建一个针对海上风电场在复杂海况下的动态响应模型。该模型不仅考虑了不同风速条件的影响,还引入了波浪和水流对风机塔架及基础结构的影响。通过仿真验证系统的有效性,并探索最佳控制参数设置以提高整体性能和稳定性。本教程展示了如何在Simulink中实现一个海上风电场在复杂海况下的动态响应仿真模型,并分析其性能。通过这种方式,我们不仅可以验证所提出的技术手段在提高海上风电场稳定性和效率方面的有效性,还能进一步探索优化参数以适应特定的应用场景。

xiaoheshang_123的博客 167

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

蓝牙模块HM-10手册

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

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

二叉堆-堆排序

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

qq_44606649的博客 910

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an &ldquo;advanced algorithms&rdquo; book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

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

一、什么是二叉堆

远走的兔子博客 3201

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

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

二叉堆的概念 二叉堆,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、付费专栏及课程。

余额充值